设计模式:工厂vs工厂方法vs抽象工厂


183

我正在从网站上阅读设计模式

我在这里读到了有关Factory,Factory方法和Abstract工厂的信息,但是它们是如此混乱,在定义上不清楚。根据定义

工厂-创建对象而不将实例化逻辑暴露给客户端,并通过通用接口引用新创建的对象。是Factory Method的简化版本

工厂方法-定义用于创建对象的接口,但让子类决定要实例化的类,并通过通用接口引用新创建的对象。

抽象工厂-提供用于创建相关对象族的接口,而无需显式指定其类。

我还查看了有关抽象工厂与工厂方法的其他stackoverflow线程,但是在那里绘制的UML图使我的理解更糟。

谁能告诉我

  1. 这三种模式有何不同?
  2. 什么时候使用?
  3. 还有可能的话,是否有与这些模式相关的Java示例?

3
在寻找与OP大致相同的问题的答案时,我发现了这篇文章:从No Factory到Factory Method。它通过跟踪示例项目的演变来提供洞察力(标题中提到的工厂方法是进化步骤之一)。
尼克·阿列克谢夫

Answers:


251

所有这三种Factory类型都执行相同的操作:它们是“智能构造函数”。

假设您希望能够创建两种水果:Apple和Orange。

Factory是“固定的”,因为您只有一个实现,没有子类。在这种情况下,您将拥有一个像这样的类:

class FruitFactory {

  public Apple makeApple() {
    // Code for creating an Apple here.
  }

  public Orange makeOrange() {
    // Code for creating an orange here.
  }

}

用例:构造Apple或Orange太复杂了,无法在构造器中进行处理。

工厂方法

当您在类中进行了一些通用处理,但又想改变您实际使用哪种水果时,通常使用工厂方法。所以:

abstract class FruitPicker {

  protected abstract Fruit makeFruit();

  public void pickFruit() {
    private final Fruit f = makeFruit(); // The fruit we will work on..
    <bla bla bla>
  }
}

...然后您可以FruitPicker.pickFruit()通过在子类中实现工厂方法来重用常用功能:

class OrangePicker extends FruitPicker {

  @Override
  protected Fruit makeFruit() {
    return new Orange();
  }
}

抽象工厂

当您希望能够创建需要“相同种类”并具有一些通用基类的整个对象系列时,抽象工厂通常用于诸如依赖注入/策略之类的事情。这是一个与水果相关的模糊示例。这里的用例是我们要确保我们不会意外地在Apple上使用OrangePicker。只要我们从同一家工厂得到我们的水果和捡拾器,它们就会匹配。

interface PlantFactory {

  Plant makePlant();

  Picker makePicker(); 

}

public class AppleFactory implements PlantFactory {
  Plant makePlant() {
    return new Apple();
  }

  Picker makePicker() {
    return new ApplePicker();
  }
}

public class OrangeFactory implements PlantFactory {
  Plant makePlant() {
    return new Orange();
  }

  Picker makePicker() {
    return new OrangePicker();
  }
}

8
+1这是我对这些模式的最相似的答案。添加调用代码示例(客户端)也有帮助吗?让我很困扰的问题是:我们可以说抽象工厂模式只是通过工厂方法模式进行工厂扩展(如果是这样,那么我很清楚这个话题)?
croraf 2014年

9
这是我多年来寻找的示例。
塔兹廷戈

这是一个很棒的解释!谢谢!
安德烈·安德拉德

@AndréAndrade如何调用工厂方法?一个小的代码示例:)这将清除我对其用法的怀疑
Arnab Dutta

25
  1. 这三种模式有何不同?

工厂:创建对象时不将实例化逻辑暴露给客户端。

工厂方法:定义用于创建对象的接口,但让子类决定实例化哪个类。Factory方法允许类将实例化延迟到子类

抽象工厂:提供一个用于创建相关或相关对象族的接口,而无需指定其具体类。

AbstractFactory模式使用组合将创建对象的责任委托给另一个类,而Factory方法设计模式使用继承并依赖于派生类或子类来创建对象

  1. 什么时候使用?

工厂:客户只需要一个类,而不在乎它所获得的具体实现。

工厂方法:客户不知道在运行时需要创建什么具体的类,而只是想获得一个可以完成此工作的类。

AbstactFactory: 当您的系统必须创建多个产品系列时,或者您想要提供产品库而不公开实现细节时。

抽象工厂类通常使用工厂方法来实现。工厂方法通常在模板方法中调用。

  1. 还有可能的话,是否有与这些模式相关的Java示例?

工厂和工厂方法

意图:

定义用于创建对象的接口,但让子类确定要实例化的类。Factory Method使类将实例化延迟到子类。

UML图

在此处输入图片说明

产品:它定义了Factory方法创建的对象的接口。

ConcreteProduct:实现产品界面

创建者:声明工厂方法

ConcreateCreator: 实现Factory方法以返回ConcreteProduct的实例

问题陈述:使用定义游戏界面的工厂方法创建游戏工厂。

程式码片段:

工厂模式。什么时候使用工厂方法?

与其他创作模式的比较:

  1. 设计从使用工厂方法(较不复杂,更可定制的子类激增)开始,并随着设计师发现需要更多灵活性的地方而向抽象工厂,原型或生成器(更灵活,更复杂)发展。

  2. 抽象工厂类通常使用工厂方法来实现,但是它们也可以使用原型来实现。

进一步阅读参考:来源制作设计模式


对于Factory Method,它不应该定义一个超类吗?
Tony Lin

21

Factory-单独的Factory类,用于创建复杂的对象。

例如:FruitFactory类创建Fruit对象

class FruitFactory{

public static Fruit getFruit(){...}

}

工厂方法 -无需为工厂提供整个单独的类,只需在该类本身中添加一个方法作为工厂即可。

例如:

Calendar.getInstance() (Java's Calendar)

抽象工厂方法 -工厂工厂

例如:假设我们要为计算机零件建造工厂。因此,有几种类型的计算机,例如笔记本电脑,台式机和服务器。

因此,对于每种计算机类型,我们都需要工厂。因此,我们创建了一个如下所示的高级工厂工厂

ComputerTypeAbstractFactory.getComputerPartFactory(String computerType) ---> This will return PartFactory which can be one of these ServerPartFactory, LaptopPartFactory, DesktopPartFactory.

现在这三个本身又是工厂。(您将要处理PartFactory本身,但实际上,将根据您在抽象工厂中提供的内容进行单独的实现)

  Interface-> PartFactory. getComputerPart(String s), 
Implementations -> ServerPartFactory, LaptopPartFactory, DesktopPartFactory.

Usage:
new ComputerTypeAbstractFactory().getFactory(“Laptop”).getComputerPart(“RAM”)

编辑:根据注释中的反对意见进行编辑,以为Abstract Factory提供确切的接口。


1
其背后的想法ComputerFactory是,您将拥有一个通用的创建界面(getScreen(); getKeyboard(); getDiskdrive(); ...),而不是您建议的每种计算机类型的界面。如果在同一条语句中使用相同的单词两次,则会闻到一个设计问题:Laptop Factory.get Laptop Part()。
xtofl 2012年

不,不,不要完全自己编写代码。这只是一种理解的动物。如果要使用接口的确切示例,请在此处。对象:接口-> ComputerPart,实现-> RAM,HDD,处理器工厂:接口-> PartFactory。getComputerPart(String s),实现-> ServerPartFactory,LaptopPartFactory,DesktopPartFactory。抽象工厂:ComputerType.getPartFactory(“ String s”)用法:new ComputerType()。getFactory(“ Laptop”)。getComputerPart(“ RAM”)
Ravi K

2
我已更新答案,以解决您的问题。实际上抽象工厂不过是工厂的事实而已。我给出了较早的示例,仅供参考(假设读者在实际实现时会注意接口)。仍然感谢您的通知。它总是有待改进。:)
Ravi K

abstract Factory,不是工厂的工厂……这是一个abstract classinterface能够创建将用不同的混凝土工厂实现/扩展的对象的工厂。有关代码的详细信息,请参见接受的答案。并且请相应地删除或编辑您的答案。
朱利安__

我喜欢工厂方法的解释,它的简洁程度足以揭示其为何如此命名。在这种模式下,工厂是方法,而不是类,该类通常不是将实例化方法分组的助手实用程序,而是自己有意义的类。不幸的是,其他更详尽的答案错过了这一点。
wlnirvana

11

每种设计模式都可以蓬勃发展,以帮助确保不触碰书面的有效代码。大家都知道,一旦我们接触到工作代码,现有的工作流程就会出现缺陷,并且需要做更多的测试以确保我们不会破坏任何东西。

工厂模式根据输入条件创建对象,从而确保您无需编写代码(例如创建该类对象或其他类对象)。一个很好的例子是旅游网站。一个旅行网站只能提供旅行(飞机,火车,公共汽车)或/,并提供酒店或/并提供旅游景点套票。现在,当用户选择下一步时,网站需要决定需要创建哪些对象。它是否也应该仅创建旅行或酒店对象。

现在,如果您打算将另一个网站添加到您的投资组合中,并且您相信可以使用同一核心,例如拼车网站(现在可以搜索出租车并在线付款),则可以在核心使用抽象工厂。这样,您就可以租用另一家出租车和拼车工厂。

两家工厂彼此之间没有任何关系,因此它是一个很好的设计,可以将它们保留在不同的工厂中。

希望现在清楚了。请再次学习该网站,并牢记此示例,希望它将对您有所帮助。我真的希望我已经正确表示了模式:)。


3

对于这个答案,我参考“四人帮”一书。

本书中没有 “工厂”,“简单工厂”或“虚拟工厂”的定义。通常,当人们谈论“工厂”模式时,他们可能谈论的是创建类的特定对象的东西(而不是“构建器”模式)。它们可能会或可能不会引用“工厂方法”或“抽象工厂”模式。任何人都可以实施“工厂”,因为这不是一个正式的术语(请记住,有些人,公司或社区可以拥有自己的词汇)。

本书包含“抽象工厂”和“工厂方法”的定义。

这是本书的定义,并简要解释了为什么两者都会如此令人困惑。我省略了代码示例,因为您可以在其他答案中找到它们:

工厂方法(GOF):定义用于创建对象的接口,但让子类决定实例化哪个类。Factory Method使类将实例化延迟到子类。

抽象工厂(GOF):提供一个用于创建相关或相关对象族的接口,而无需指定其具体类。

混乱的根源:通常,可以将在“工厂方法”模式中使用的类称为“工厂”。此类根据定义是抽象的。这就是为什么容易将此类称为“抽象工厂”的原因。但这只是班级的名称。您不应将其与“ Abstract Factory”模式(类名!=模式名)混淆。在“抽象工厂”模式不同-它并没有使用抽象类; 它定义了一个接口(不一定是编程语言接口),用于创建一个较大的对象或彼此相关或必须以特定方式创建的对象的各个部分。


2
AbstractProductA, A1 and A2 both implementing the AbstractProductA
AbstractProductB, B1 and B2 both implementing the AbstractProductB

interface Factory {
    AbstractProductA getProductA(); //Factory Method - generate A1/A2
}

使用工厂方法,用户可以创建AbstractProductA的A1或A2。

interface AbstractFactory {
    AbstractProductA getProductA(); //Factory Method
    AbstractProductB getProductB(); //Factory Method
}

但是Abstract Factory具有不止一种工厂方法(例如2种工厂方法),使用这些工厂方法将创建一组对象/相关对象。使用Abstract Factory,用户可以创建AbstractProductA,AbstractProductB的A1,B1对象


0

没有人引用原始书《设计模式:可重用的面向对象软件的元素》,该书在“讨论创建模式”部分的前两段给出了答案(重点是我的):

有两种常用的方法可以根据系统创建的对象类别对其进行参数化。一种方法是对创建对象的类进行类化。这对应于使用“工厂方法(107)”模式。这种方法的主要缺点是,可能需要一个新的子类来更改产品的类。这样的变化可以级联。例如,当产品创建者本身是通过工厂方法创建的时,那么您还必须覆盖其创建者。

参数化系统的另一种方法更多地依赖于对象组成:定义一个负责了解产品对象类的对象,并将其作为系统的参数。这是抽象工厂(87),生成器(97)和原型(117)模式的关键方面。这三者都涉及创建一个新的“工厂对象”,其职责是创建产品对象。抽象工厂具有几个类的工厂对象生产对象。Builder具有使用相对复杂的协议以增量方式构建复杂产品的工厂对象。原型具有通过复制原型对象来构建产品的工厂对象。在这种情况下,工厂对象和原型是同一对象,因为原型负责返回产品。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.