221

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

在那里我读到了工厂、工厂方法和抽象工厂,但它们太混乱了,定义不清楚。根据定义

工厂 - 创建对象而不向客户端公开实例化逻辑,并通过通用接口引用新创建的对象。是工厂方法的简化版

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

抽象工厂 - 提供用于创建一系列相关对象的接口,而无需明确指定它们的类。

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

谁能告诉我

  1. 这三种模式有何不同?
  2. 什么时候用哪个?
  3. 如果可能的话,还有与这些模式相关的任何 java 示例吗?
4

9 回答 9

316

所有三种工厂类型都做同样的事情:它们是“智能构造函数”。

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

工厂

工厂是“固定的”,因为您只有一个没有子类化的实现。在这种情况下,您将有一个这样的类:
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();
  }
}
于 2012-10-23T12:12:15.073 回答
26
  1. 这三种模式有何不同?

工厂:创建对象而不向客户端公开实例化逻辑。

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

抽象工厂:提供用于创建相关或依赖对象系列的接口,而无需指定它们的具体类。

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

  1. 什么时候用哪个?

工厂:客户只需要一个类,并不关心它得到了哪个具体的实现。

工厂方法:客户端不知道在运行时需要创建哪些具体类,但只想获得一个可以完成这项工作的类。

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

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

  1. 如果可能的话,还有与这些模式相关的任何 java 示例吗?

工厂和工厂方法

意图:

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

UML图

在此处输入图像描述

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

ConcreteProduct:实现产品接口

创建者:声明工厂方法

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

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

代码片段:

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

与其他创作模式的比较:

  1. 设计开始使用工厂方法(不太复杂,更可定制,子类激增),随着设计人员发现需要更大灵活性的地方, 向抽象工厂、原型或构建器(更灵活、更复杂)发展

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

进一步阅读的参考资料:Sourcemaking 设计模式

于 2016-03-07T18:41:09.290 回答
22

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”)

编辑:根据评论中的反对意见进行编辑,为抽象工厂提供准确的接口。

于 2012-10-23T11:47:05.110 回答
12

每个设计模式都努力帮助确保不触及书面的、工作的代码。我们都知道,一旦我们接触到工作代码,现有的工作流程就会出现缺陷,需要做更多的测试来确保我们没有破坏任何东西。

工厂模式根据输入标准创建对象,从而确保您不需要编写如下代码:

 if (this) {
     create this kind of object 
 } else { 
     that kind of object 
 }

一个很好的例子是旅游网站。旅游网站只能提供旅游(飞机、火车、巴士)或/和提供酒店或/和提供旅游景点套餐。现在,当用户选择下一步时,网站需要决定它需要创建哪些对象。它是否也应该只创建旅行或酒店对象。

现在,如果您设想将另一个网站添加到您的投资组合中,并且您认为使用相同的核心,例如,现在搜索出租车并在线支付的拼车网站,您可以在您的核心中使用抽象工厂。这样,您就可以再购买一个出租车和拼车工厂。

两个工厂之间没有任何关系,所以将它们放在不同的工厂是一个很好的设计。

希望这现在很清楚。再次研究该网站,记住这个例子,希望它会有所帮助。我真的希望我正确地表示了模式:)。

于 2012-10-23T12:05:05.780 回答
10

对于这个答案,我参考了《四人帮》这本书。

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

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

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

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

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

困惑之源:通常,可以将“工厂方法”模式中使用的类称为“工厂”。这个类根据定义是抽象的。这就是为什么很容易将这个类称为“抽象工厂”的原因。但这只是类的名称;您不应将其与“抽象工厂”模式(类名!= 模式名)混淆。“抽象工厂”模式不同——它不使用抽象类;它定义了一个接口(不一定是编程语言接口),用于创建一个或多个相互关联或必须以特定方式创建的更大对象的部分。

于 2019-08-01T10:14:14.870 回答
9

基于来自Vaskaran Sarcar 的 C# 中的设计模式,第 2 版书中的这些图像:

1. 简单工厂模式

创建对象而不向客户端公开实例化逻辑。

SimpleFactory simpleFactory = new SimpleFactory();
IAnimal dog = simpleFactory.CreateDog(); // Create dog
IAnimal tiger = simpleFactory.CreateTiger(); // Create tiger

在此处输入图像描述

2.工厂方法模式

定义一个用于创建对象的接口,但让子类决定实例化哪个类。

AnimalFactory dogFactory = new DogFactory(); 
IAnimal dog = dogFactory.CreateAnimal(); // Create dog

AnimalFactory tigerFactory = new TigerFactory();
IAnimal tiger = tigerFactory.CreateAnimal(); // Create tiger

在此处输入图像描述

3.抽象工厂模式(factory of factory)

抽象工厂提供了用于创建一系列相关对象的接口,而无需明确指定它们的类

IAnimalFactory petAnimalFactory = FactoryProvider.GetAnimalFactory("pet");
IDog dog = petAnimalFactory.GetDog(); // Create pet dog
ITiger tiger = petAnimalFactory.GetTiger();  // Create pet tiger

IAnimalFactory wildAnimalFactory = FactoryProvider.GetAnimalFactory("wild");
IDog dog = wildAnimalFactory .GetDog(); // Create wild dog
ITiger tiger = wildAnimalFactory .GetTiger();  // Create wild tiger

在此处输入图像描述

于 2020-12-16T22:14:27.937 回答
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
}

但是具有超过 1 个工厂方法(例如:2 个工厂方法)的抽象工厂,使用这些工厂方法将创建一组对象/相关对象。使用抽象工厂,用户可以创建 AbstractProductA、AbstractProductB 的 A1、B1 对象

于 2015-07-24T06:26:20.167 回答
2

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

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

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

于 2019-11-14T10:21:41.493 回答
1

工厂:或简单工厂,旨在产生一种对象的类。调用者将调用它来获取特定类型的项目。例如 SimplePizzaFactory 将通过 SimplePizzaFactory.getPizza() 生产一个简单的披萨

工厂方法工厂方法是一个简单的静态方法,它会给它所要求的对象,该工厂方法通常让调用者可以选择他想要的类型。例如 PizzaFactory.getPizza(String type),该类型可能是“经典”、“农舍”、“玛格丽塔”或“乡村特色”。

抽象工厂这只是一个工厂的工厂,所以如果你调用一个抽象工厂,它会给你一个工厂的对象。例如, AbstractPizzaFactory 会给你 VegPizzaFactory 或 NonVegPizzaFactory 然后使用 VegPizzaFactory 你可能会得到“农家”披萨。

参考文章https://www.binpress.com/factory-design-pattern/

于 2022-01-26T15:16:47.797 回答