【问题标题】:Does the Factory Method pattern violate the Open/Closed principle?工厂方法模式是否违反了开放/封闭原则?
【发布时间】:2011-01-23 18:46:00
【问题描述】:

Factory Method pattern(不要与工厂或抽象工厂模式混淆)是否违反了Open/Closed principle

更新: 为了澄清,我指的是具体类上有静态工厂方法的场景。例如(来自 FMP 上的 Wikipedia 页面):

class Complex 
{
    public static Complex fromCartesian(double real, double imag) {
        return new Complex(real, imag);
    }

    public static Complex fromPolar(double modulus, double angle) {
        return new Complex(modulus * cos(angle), modulus * sin(angle));
    }

    private Complex(double a, double b) {
       //...
    }
}

私有构造器不会阻止类被子类化,即扩展吗?

难道不需要修改类来支持新的工厂方法吗?例如,如果该类最初只有 fromCartesian,后来需要 fromPolar,那么是否必须修改该类以支持这一点?

这两个都不违反 Open/Closed 吗?

【问题讨论】:

  • 在我回答之前,我想知道您对此有何看法。你的回答会让我觉得你在寻找答案。否则,就像您将工作外包给 SO。
  • 抱歉,本来打算加个评论的,但是因为工作而跑题了。 :) 我认为它确实违反了它。如果我错了,请纠正我,但 FMP 规定私有构造函数,私有构造函数禁止扩展。此外,是否必须修改该类以支持替代实现?我正在考虑类具有静态工厂方法的情况。也许这只是 FMP 的一种风味?
  • 难道switch语句还不需要修改类吗?私有构造函数阻止扩展的问题呢?
  • 您引用的维基百科代码并不是真正的经典工厂方法模式。这很相似,但在我看来,这不是一回事。在需要工厂方法的情况下,您不会使用这样的代码。
  • 那个特定的代码并不是真的,因为像数字这样的东西通常是一种特殊情况,并且创建它们的方式并不是您的要求所要求的可配置的。但是其他一些具有私有构造函数和静态工厂方法的类(包含可能更改的业务逻辑)?是的。

标签: design-patterns factory-method open-closed-principle


【解决方案1】:

不,它根本不违反开放/封闭原则。

打开/关闭意味着您可以修改系统的工作方式,而无需修改已经存在的代码。您可以扩展代码并以不同的方式使用它,但旧代码仍然完好无损,不需要重新测试。

工厂方法模式将根据指定的参数创建不同类型的对象。如果操作正确,工厂方法实际上适用于开/关原则。但是,如果您创建一个新类,然后希望工厂方法创建该类型的新对象,则必须更改工厂方法。

虽然,如果您有某种配置文件或工厂方法读取的那种类型的文件,那么您不必更改工厂方法......只需配置文件,然后指示什么对象将由工厂方法创建。

【讨论】:

    【解决方案2】:

    工厂模式本质上并不违反OCP

    这取决于您如何进一步处理Complex 的行为。

    如果需要Complex来支持新类型Complex对象的产生,而您选择修改Complex,添加新的fromX方法来支持它们,那么这意味着Complex成为OCP 的违反者,因为必须重新打开Complex 进行修改:

    class Complex 
    {
        public static Complex fromCartesian(double real, double imag) {
            return new Complex(real, imag);
        }
    
        public static Complex fromPolar(double modulus, double angle) {
            return new Complex(modulus * cos(angle), modulus * sin(angle));
        }
    
        //class opened for modification
        public static Complex fromOtherMeans(String x , String y) {
            return new Complex(x, y);
        }
    }
    

    您可以将此问题推送到某种文本文件或属性文件中,以免除您必须更改 java 类的责任,但这并不妨碍您在此区域编写额外的逻辑解决方案以支持新类型的Complex

    根据您的设计中Complex 的使用情况(各种类型有何不同?您如何使用它们?),有一些替代选项可能适用。

    这样一种OCP 友好的替代方法是继承Complex 以提供额外的工厂方法。子类是 Complex 如何扩展但不修改的最简单说明。

    在这种情况下,另一个 OCP 友好的替代方法是更改​​ ComplexDecorator pattern。不断地装饰Complex 并能够创建Complex 的新变体尊重OCP,因为Complex 没有被修改,而是通过用新功能包装它来扩展。

    第三种选择可能是更改Complex 的结构,以便其计算由组合提供。这将使您有机会使用Strategy pattern 来区分Complex 的不同行为。

    关于工厂模式的事情是它有助于上下文代码尊重OCP。人们可能会使用上述技术之一,以便在他们的 Factory 类中保持在 OCP 的右侧,但您的同事可能会看一看对象图,质疑将对象图置于单个工厂,并将其简化回一个工厂,这将带您回到第一个示例。

    在这种情况下,与其试图改变工厂模式的实现以尊重SOLID 原则,不如考虑一下为什么要使用它

    【讨论】:

      【解决方案3】:

      不。从您的维基百科链接:

      软件实体(类、模块、函数等)应该对扩展开放,对修改关闭

      覆盖工厂方法是扩展。您正在创建一个新课程。您不会更改现有课程。您必须(希望通过您的 IoC 容器的配置)替换原始的子类。

      【讨论】:

        猜你喜欢
        • 2018-06-11
        • 2021-12-15
        • 1970-01-01
        • 2021-08-24
        • 2010-10-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多