工厂方法模式是否违反开放/封闭原则?

时间:2010-03-04 17:04:52

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

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

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

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) {
       //...
    }
}

私有构造函数是否阻止该类被子类化,即扩展?

是否不必修改课程以支持新的工厂方法?例如,如果该类最初只需要来自Caresian,后来需要使用thePolar,那么是否必须修改该类才能支持此类?

这两种情况都不违反开放/封闭吗?

3 个答案:

答案 0 :(得分:5)

工厂模式本身并不是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如何扩展但未修改的最简单说明。

在这种情况下,改变Complex的另一个OCP友好替代方案是Decorator pattern。通过创建Complex的新变体来持续装饰Complex尊重OCP,因为Complex未被修改,但通过使用新功能包装它而得到扩展。

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

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

在这种情况下,不要试图弯曲您的工厂模式的实现以尊重SOLID原则,而应考虑为什么您一直使用它

答案 1 :(得分:4)

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

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

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

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

答案 2 :(得分:2)

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

  

软件实体(类,模块,函数等)应该是可以扩展的,但是关闭以进行修改

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