什么时候应该使用工厂方法模式? (而不是组合物)

什么时候应该使用工厂方法模式? (而不是组合物)

问题描述:

作为每GOF书,Factory method pattern什么时候应该使用工厂方法模式? (而不是组合物)

定义的接口,用于创建一个对象,但让子类决定实例的类。工厂方法让类将实例化推迟到子类。该图案的

结构

public abstract class Factory { 
    public abstract IProduct createProduct(); 
    private void performCriticalJob(){ 
     IProduct product = createProduct(); 
     product.serve(); 
    } 
    public void executeJob(){ 
     //some code 
     performCriticalJob(); 
     //some more code 
    } 
} 


public interface IProduct { 
    public void serve(); 
} 
  1. 厂需要的对象(其具体类是不知道或其具体的类可以按照不同的应用类型变化)来执行一个任务。

  2. 因为它不知道要实例化哪个类,所以需要为所需对象的类型设置一个标准契约,将此契约置于接口中。

  3. 基本工厂类声明abstract方法返回如上定义的interface类型的对象。 它允许子类决定并提供对象创建的实现。

  4. 要完成任务,需要一个对象,只需调用abstract方法即可获取该对象。

问题青睐组成了继承。 上面的工厂方法使用继承来获得具体产品。另外,子类需要实现createProduct,它将创建并返回ConcreteProduct。而不是Subclassing Factory类,如果抽象方法被从中删除(这使得Factory类成为非抽象类)。现在Factory类可以由新类组成,具体的产品对象可以像下面的例子那样注入。

为了实现Factory方式模式定义的场景中的意图,为什么只是正常的多态性没有被使用如下?我知道工厂方法模式有更多的东西我失踪了,但通过继承的偏好构成,我发现下面的方式,以相同的情况下解决同样的问题,更好的方式在Factory method的方式。 Factory method优于以下方法的优点是什么?

public abstract class Factory { 
    private void performCriticalJob(IProduct product){ 
     product.serve(); 
     //some code 
    } 
    public void executeJob(IProduct product){ 
     //some code 
     performCriticalJob(product); 
     //some more code 
    } 
} 

现在不是要求用户创建子工厂类,并通过实现createProduct方法退回产品的具体对象,用户可以直接提供实施IProduct到executeJob具体类的对象。

[编辑]感谢回答和评论,但同样的想法表达在评论和回答中,我也有过,这也带来了一些困惑。我研究了工厂方法模式的GOF。它使用了一个框架的例子来创建各种类型的文档。我的问题是这些研究后引起的疑问。

这些网站和博客除了反映了作者对模式的理解之外,他/她可能或可能没有阅读,理解模式的实际意图。了解课程并不是主要目标。应该研究设计模式,考虑哪些场景以及哪些问题是遵循良好面向对象原则的最佳解决方案(或者最少违反它们,并且有充分理由这样做)。最好的解决方案是任何design pattern解释的解决方案。 GOF是一本很好解释它的标准书。但是这个问题的主要原因还是有一些空白或者疑问。

+0

在第二个示例中,IProduct如何实例化? – jrahhali

+1

我在你的代码片段中看不到多态:/ –

+0

通过多态我的意思是接受Interface IProduct类型参数的方法。用户可以直接向'executeJob'提供实现'IProduct'的具体类的对象,而不是要求用户创建子工厂类并回应产品的具体对象。 –

我知道工厂方法模式有更多的东西,我很想念而是在继承favouting组成要去,我发现下面的方法,来解决同样的问题,在相同的情况下

有几种使用工厂方法时,如你的问题,你得到模式,而不是普通的老成分的优点:您可以创建一个F:

1的关切和开放 - 封闭原则分离每个相关对象组的一个子类。此工厂子类负责仅创建属于特定组的产品。 ABCProductFactory只会涉及创建ABCProduct1,ABCProduct2CDEProductFactory将只涉及创建CDEProduct1,CDEProduct2等。对于每个新产品组,您都会创建一个新的子类,而不是修改现有的类。如果你使用构图方法,其他一些课程将负责创建产品并将其传递到您的Factory。随着产品品种的增加,如ZZZProduct1ZZZProduct2等等,这个类很快会爆炸到一个巨大的尺寸,有太多的if-else条件来检查要创建哪个产品子类。你最终会意识到这一点,并定义一个类来创建每个相关的产品组。

2.产品创建和产品加工具有合同:工厂方法图案非常相似,在这种情况下,模板方法图案,因为它指定需要被上执行的操作的模板对象创建后。这使您可以确保一旦创建产品,它将始终与工厂创建的任何其他产品一样经历相同的步骤。将此与组合进行比较,在您的问题中没有固定合同,即IProduct创建后应该经过的步骤。我可以创建一个名为Factory2的类,并使用一个称为performCriticalJobpublic方法。没有什么强迫我在Factory2中有executeJob方法。即使我将executeJob方法添加到Factory2,但没有任何东西让我在executeJob内部呼叫performCriticalJob。您可以通过使用模板模式来解决此问题。

现在应该清楚工厂方法模式基本上将对象创建和对象处理绑定在一个类中。以你的作文为例,你会有很多动人的作品,没有人管理他们应该如何一起工作。

底线:在你的情况,当你想创建对象和对象的处理有一个固定的合同,使得所有物体都要经过一次创建相同的处理使用工厂方法模式。在创建对象后需要遵循的步骤不需要任何合同的情况下,使用您的组合示例。

+0

第二点的+1。我想我正在寻找一些答案。但是,第1点仍然没有什么疑问,因为与其他语句不同,可以有多少种产品,每种产品都可以创建产品并在工厂类中注入。但是,是的,这里没有执行合同......我希望有更多好的想法,并且如果没有其他这样的想法,那么我会将这个答案标记为已接受。 –

+0

@ nits.kk创建每个对象的一个​​类。 100个产品的100个工厂?你最好用'new'代替!你看,一家工厂应该封装相关产品的创建。让每个产品对应一个工厂类是没有价值的。 (我故意选择忽略术语*可疑*但它确实对它有负面含义) – CKing

+0

如果产品具有相同的超级类型(遵循同一合同)并且是相关的(与同一工厂有关),则遵循工厂方法模式'createProduct'必须决定创建哪个产品(简单的方法可以根据参数切换大小写)。构成方式也可以做同样的事情,并根据参数注入决定的产品。 –

再次阅读您所提供的定义:

定义一个接口,用于创建对象,但是让子类决定哪一个类实例。工厂方法让类将实例化推迟到子类。

这有点违背你的第一个声明:

厂需要一个对象(其具体类是不知道还是其具体的类可以按照不同的应用类型更改)执行任务

出厂目的创建对象,而不是执行任务

事实上,事件如果它将执行任务,它只能为你创建对象。 从工厂获得对象后,您可以执行关键任务。

而且在继承约青睐组成,工厂方法可以组成对象为你以及和传递回一个对象组成。

有工厂模式的许多很好的例子 - 在Wikipedia例如和blackwasp

编辑 - 关于GoF的Application例如

Application的GoF的示例使用了一个Factory MethodTemplate MethodApplication定义了工厂方法及其周围的一些操作,但Application的子类决定要创建哪个Document

你有建议,不要使用工厂方法。相反,要在其他地方创建Document并“注入”Application(也称为依赖注入)。 您尚未描述Document将在何处创建(它可能仍然是工厂)。
现在,Application子类对创建Document没有任何控制权。这完全改变了系统的行为和设计。

这并不意味着它的坏或好,它只是一种不同的方法。
在现实生活中,您必须仔细检查手头的问题并确定哪种设计最适合。

+0

@Overir Winegarten @Funir酒园这些确切的想法,我请了一下,但请从'GOF'应用程序创建文档框架示例解释模式,它将带来一些见解:) –

+0

@ nits.kk更新了我的答案 –

+0

按照工厂方法标准结构代码的用户将对工厂进行子类化并为创建具体产品的createProduct提供实现。因此,在第二种解决方案中,类似的情况是,用户可以代替子类化基类来创建实例,然后在创建具体产品后注入具体产品。 –

您的问题是,您坚持认为您的Factory类只有一种类型的客户端通过扩展它(代码#1)或将新创建的IProduct传递到其方法(代码# 2)。这种客户的全部目的是使Factory接收新创建的IP产品的能力。

那些不关心上述所有事情的普通客户呢!这些甚至不关心班级是否为工厂。因此,他们不需要像代码#2那样需要IProduct的方法。

确实,您应该将您的Factory类重命名为其他类(例如,XXX),该类不是“工厂”!但它的一些方法是“工厂”。你看,模式名称是“工厂方法”,而不是“工厂”或“工厂对象”。相比之下,在抽象工厂模式中,抽象工厂实际上是工厂对象。

P/S:一种合适的组合方法是将抽象工厂传递给XXX的构造函数。