ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

工厂 - 创建对象而不向客户端公开实例化逻辑,并通过通用接口引用新创建的对象。是Factory Method的简化版Factory Method - 定义了一个创建对象的接口,但是让子类决定实例化哪个类,并通过一个通用接口引用新创建的对象。抽象工厂 - 提供用于创建一系列相关对象的接口,而无需明确指定它们的类。

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

谁能告诉我

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

当我在寻找与 OP 大致相同的问题的答案时,我发现了这篇文章:From No Factory to Factory Method。它通过跟踪示例项目的演变来提供洞察力(标题中提到的工厂方法是演变步骤之一)。
阅读以下文章后,我偶然发现了这一点,该文章很好地描述了该问题:"Codeproject- Factory methode vs. abstract factory

Y
Yogesh Umesh Vaity

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

假设您希望能够创建两种水果: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();
  }
}

抽象工厂

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();
  }
}

+1这是与我对这些模式的理解最相似的答案。添加调用代码(客户端)的示例也会有帮助吗?困扰我很多的问题是:我们可以说抽象工厂模式只是工厂方法模式的工厂扩展(如果这是真的,我很清楚这个话题)?
这是我多年来一直在寻找的例子。
@AndréAndrade 如何调用工厂方法?请提供一个小代码示例 :) 这将消除我对其用法的疑问
R
Ravindra babu

这三种模式有何不同?

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

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

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

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

什么时候用哪个?

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

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

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

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

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

工厂和工厂方法

意图:

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

UML diagram

https://i.stack.imgur.com/HF19B.gif

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

ConcreteProduct:实现产品接口

创建者:声明工厂方法

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

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

代码片段:

Factory Pattern. When to use factory methods?

与其他创作模式的比较:

设计开始使用工厂方法(不太复杂,更可定制,子类激增),随着设计人员发现需要更多灵活性的地方,向抽象工厂、原型或构建器(更灵活、更复杂)发展抽象工厂类通常使用工厂实现方法,但它们也可以使用 Prototype 来实现

进一步阅读参考:Sourcemaking design-patterns


对于工厂方法,不应该定义一个超类吗?
R
Ravi K

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

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


ComputerFactory 背后的想法是您有一个通用的创建界面 (getScreen(); getKeyboard(); getDiskdrive(); ...),而不是您建议的每种计算机类型的界面。如果您在同一语句中使用相同的词两次:LaptopFactory.getLaptopPart(),您可能会发现设计问题。
不不不,不要完全按照代码本身。这只是一个理解的比喻。如果你想要接口的确切示例,这里就是。对象:接口-> ComputerPart,实现-> RAM,HDD,处理器工厂:接口-> PartFactory。 getComputerPart(String s),实现 -> ServerPartFactory,LaptopPartFactory,DesktopPartFactory。抽象工厂:ComputerType.getPartFactory(“String s”) 用法:new ComputerType().getFactory(“Laptop”).getComputerPart(“RAM”)
我已更新答案以解决您的问题。实际上抽象工厂只不过是工厂的工厂而已。我给出了前面的示例仅供参考(假设读者在实际实现时会处理接口)。还是谢谢通知。改进总是好的。 :)
没有 abstract Factory 不是工厂的工厂...它是一个 abstract classinterface 能够创建将使用不同的具体工厂实现/扩展的对象。有关代码详细信息,请参阅接受的答案。请相应地删除或编辑您的答案。
我喜欢工厂方法的解释,它简洁到足以揭示它为什么如此命名。在这种模式下,工厂是方法,而不是类,它通常不是对实例化方法进行分组但本身就有意义的辅助实用程序。不幸的是,其他更详细的答案错过了这一点。
H
Hamed Naeemaei

基于来自 Design Patterns in C#, 2nd Edition by Vaskaran Sarcar 本书的图片:

1. 简单工厂模式

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

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

https://i.stack.imgur.com/wtWBJ.png

2.工厂方法模式

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

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

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

https://i.stack.imgur.com/DC3aW.png

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

https://i.stack.imgur.com/yY7wB.png


100% 清晰度。被低估的答案
这实际上让我感到困惑。为什么不以您可以像这样使用它的方式创建一个抽象 AnimalFactoryIAnimal animal = AnimalFactory.create("dog");。为什么每种类型都需要一个单独的工厂,因此需要“工厂工厂”?这样做有什么收获?
@Nom1fan 如果我们有一个简单的系统,我们可以写得这么简单,但是当系统变得复杂时,工厂的工厂有助于控制复杂性。
P
Pavel Sapehin

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

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

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

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

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

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

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


Y
Yogesh Umesh Vaity

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

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

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

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

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

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

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


k
kleopatra
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 对象


C
Community

没有人引用原著Design Patterns: Elements of Reusable Object-Oriented Software,它在“创造模式的讨论”部分的前两段中给出了答案(强调我的):

有两种常用方法可以通过系统创建的对象类来参数化系统。一种方法是对创建对象的类进行子类化;这对应于使用工厂方法 (107) 模式。这种方法的主要缺点是它可能需要一个新的子类来改变产品的类。这种变化可以级联。例如,当产品创建者本身由工厂方法创建时,您也必须覆盖其创建者。另一种参数化系统的方法更多地依赖于对象组合:定义一个负责了解产品对象类的对象,并使其成为系统的参数。这是抽象工厂 (87)、构建器 (97) 和原型 (117) 模式的关键方面。这三个都涉及创建一个新的“工厂对象”,其职责是创建产品对象。抽象工厂具有生产多个类对象的工厂对象。 Builder 让工厂对象使用相应复杂的协议逐步构建复杂的产品。原型具有通过复制原型对象来构建产品的工厂对象。在这种情况下,工厂对象和原型是同一个对象,因为原型负责返回产品。