ChatGPT解决这个技术问题 Extra ChatGPT

抽象工厂和工厂设计模式有什么区别?

我知道有很多关于这两种模式之间差异的帖子,但有一些我找不到。

从我一直在阅读的内容中,我看到工厂方法模式允许您定义如何创建单个具体产品,但对客户隐藏实现,因为他们将看到通用产品。我的第一个问题是关于抽象工厂的。它的作用是允许您在其中创建具体对象系列(这可能取决于您使用的特定工厂),而不仅仅是单个具体对象?抽象工厂是否只返回一个非常大的对象或许多对象,具体取决于您调用的方法?

我的最后两个问题是关于一个我无法完全理解的单引号,我在很多地方都看到过:

两者之间的一个区别在于,对于抽象工厂模式,一个类通过组合将对象实例化的责任委托给另一个对象,而工厂方法模式使用继承并依赖子类来处理所需的对象实例化。

我的理解是工厂方法模式有一个 Creator 接口,这将使 ConcreteCreator 负责知道要实例化哪个 ConcreteProduct。这就是使用继承来处理对象实例化的意思吗?

现在关于那句话,抽象工厂模式究竟是如何通过组合将对象实例化的责任委托给另一个对象的?这是什么意思?看起来抽象工厂模式在我看来也使用继承来完成构建过程,但我仍然在学习这些模式。

任何帮助,尤其是最后一个问题,将不胜感激。

从客户的角度来看“实例是如何创建的”,将有助于您理解报价。
@nawfal,该线程中的答案很糟糕。

T
Tom Dalling

两者的区别

“工厂方法”和“抽象工厂”的主要区别在于工厂方法是方法,而抽象工厂是对象。我想很多人会混淆这两个术语,并开始互换使用它们。我记得当我学习它们时,我很难找到确切的区别。

因为工厂方法只是一个方法,它可以在子类中被覆盖,因此你引用的后半部分:

...工厂方法模式使用继承并依赖子类来处理所需的对象实例化。

引用假定一个对象在这里调用它自己的工厂方法。因此,唯一可以改变返回值的就是子类。

抽象工厂是一个拥有多个工厂方法的对象。看看你报价的前半部分:

...使用抽象工厂模式,一个类通过组合将对象实例化的责任委托给另一个对象...

他们说的是有一个对象 A,他想制作一个 Foo 对象。与其创建 Foo 对象本身(例如,使用工厂方法),不如使用不同的对象(抽象工厂)来创建 Foo 对象。

代码示例

为了向您展示差异,这里是使用的工厂方法:

class A {
    public void doSomething() {
        Foo f = makeFoo();
        f.whatever();   
    }

    protected Foo makeFoo() {
        return new RegularFoo();
    }
}

class B extends A {
    protected Foo makeFoo() {
        //subclass is overriding the factory method 
        //to return something different
        return new SpecialFoo();
    }
}

这是一个正在使用的抽象工厂:

class A {
    private Factory factory;

    public A(Factory factory) {
        this.factory = factory;
    }

    public void doSomething() {
        //The concrete class of "f" depends on the concrete class
        //of the factory passed into the constructor. If you provide a
        //different factory, you get a different Foo object.
        Foo f = factory.makeFoo();
        f.whatever();
    }
}

interface Factory {
    Foo makeFoo();
    Bar makeBar();
    Aycufcn makeAmbiguousYetCommonlyUsedFakeClassName();
}

//need to make concrete factories that implement the "Factory" interface here

这是一个很好的解释。但是,最重要的部分没有得到解答,那就是:何时使用一种模式,何时使用另一种模式?
不确定这是否正确。可以肯定的是,工厂方法是一种以工厂方法命名的设计模式,但涉及到类结构和继承。这不是一个单一的方法。
那么这样说是否正确:Factory 方法可以是所有常规类中具有不同用途的方法。但是抽象工厂是一个客户使用的类/对象,只负责在一个家庭中创建一些产品?
@HieuM.Nguyen 这就是我的理解
回答 Aviv Cohn,它是一个方法 name,在子类中有多个覆盖。它不是一个独立的方法定义。示例代码通过 makeFoo 的两个实现演示了这一点。
P
Pietro Di Bello

抽象工厂使用抽象方法创建一个基类,为应该创建的对象定义方法。派生基类的每个工厂类都可以创建自己的每个对象类型的实现。

https://upload.wikimedia.org/wikipedia/commons/b/b8/AbstractFactory.png

工厂方法只是用于在类中创建对象的简单方法。它通常添加到聚合根中(Order 类有一个名为 CreateOrderLine 的方法)

https://upload.wikimedia.org/wikipedia/commons/e/ed/Factory_Method_UML_class_diagram.png

抽象工厂

在下面的示例中,我们设计了一个接口,以便我们可以将队列创建与消息传递系统分离,因此可以为不同的队列系统创建实现,而无需更改代码库。

interface IMessageQueueFactory
{
  IMessageQueue CreateOutboundQueue(string name);
  IMessageQueue CreateReplyQueue(string name);
}

public class AzureServiceBusQueueFactory : IMessageQueueFactory
{
      IMessageQueue CreateOutboundQueue(string name)
      {
           //init queue
           return new AzureMessageQueue(/*....*/);
      }

      IMessageQueue CreateReplyQueue(string name)
      {
           //init response queue
           return new AzureResponseMessageQueue(/*....*/);
      }

}

public class MsmqFactory : IMessageQueueFactory
{
      IMessageQueue CreateOutboundQueue(string name)
      {
           //init queue
           return new MsmqMessageQueue(/*....*/);
      }

      IMessageQueue CreateReplyQueue(string name)
      {
           //init response queue
           return new MsmqResponseMessageQueue(/*....*/);
      }
}

工厂方法

HTTP 服务器的问题是我们总是需要对每个请求进行响应。

public interface IHttpRequest
{
    // .. all other methods ..

    IHttpResponse CreateResponse(int httpStatusCode);
}

如果没有工厂方法,HTTP 服务器用户(即程序员)将被迫使用特定于实现的类,这违背了 IHttpRequest 接口的目的。

因此我们引入了工厂方法,使得响应类的创建也被抽象掉了。

概括

不同之处在于包含工厂方法的类的预期目的不是创建对象,而抽象工厂应该只用于创建对象。

使用工厂方法时应该小心,因为在创建对象时很容易破坏 LSP (Liskov Substitution principle)。


为什么我们需要混凝土产品?
因为没有人愿意投资想法。
抽象工厂不应仅创建 Button() 来创建“相关产品系列”。例如,规范的 GoF 示例创建 ScrollBar()Window()。优点是抽象工厂可以在其多个产品中强制执行一个共同的主题。
雅科是对的。考虑到两个 UML 图本质上是相同的(除了抽象工厂 UML 是错误的)。在这两种情况下,客户端都在调用工厂方法来创建单个产品。
@AndrewS:回答你的问题。如果我们不需要为同一个抽象(接口)提供不同的具体产品(类),我们可能需要构建器模式而不是工厂模式。 (迟到总比不到好 ;))
V
V. S.

AbstractFactory 和 Factory 设计模式的区别如下:

工厂方法仅用于创建一种产品,但抽象工厂用于创建相关或依赖产品的系列。

工厂方法模式向客户端公开了一个用于创建对象的方法,而在抽象工厂的情况下,它们公开了一系列相关对象,这些对象可能由这些工厂方法组成。

工厂方法模式隐藏了单个对象的构造,而抽象工厂隐藏了一系列相关对象的构造。抽象工厂通常使用(一组)工厂方法来实现。

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

工厂方法模式背后的想法是,它允许客户端不知道在运行时需要创建哪些具体类,但只想获得一个类来完成这项工作,而抽象工厂模式是当您的系统必须创建多个产品系列或您想要提供产品库而不暴露实现细节时,最好使用它。!

https://i.stack.imgur.com/S4QMP.jpg

抽象工厂模式实现:

https://i.stack.imgur.com/C2F8L.jpg


嗯,不确定抽象工厂示例。我认为形状工厂和颜色工厂应该实现相同的方法。但是,如果我是对的,那么样本就没有意义了。
要点是正确的;但是,这两个图表都是完全错误的并且非常具有误导性。有关抽象工厂的准确模型,请参见@Trying 的下图。
我不得不同意这两个图表确实非常具有误导性。我在 tutorialspoint 网站上看到过它们,老实说,我不是 100% 同意它们。虽然描述看起来不错
这是非常具有误导性的。
超过 50 次投票,而且图表非常错误。证明您不能相信 SO 上的许多设计模式答案。
j
jaco0646

抽象工厂和工厂方法的主要区别在于抽象工厂是通过组合实现的;但是工厂方法是通过继承实现的。

是的,您没看错:这两种模式之间的主要区别在于旧的 composition vs inheritance 辩论。

UML 图可以在 (GoF) 书中找到。我想提供代码示例,因为我认为结合该线程中前两个答案的示例将比单独的任何一个答案提供更好的演示。此外,我在类和方法名称中使用了书中的术语。

抽象工厂

这里最重要的一点是抽象工厂被注入到客户端。这就是为什么我们说抽象工厂是由组合实现的。通常,依赖注入框架会执行该任务。但 DI 不需要框架。第二个关键点是这里的具体工厂不是工厂方法的实现!工厂方法的示例代码如下所示。最后,要注意的第三点是产品之间的关系:在这种情况下是出站和回复队列。一个混凝土工厂生产 Azure 队列,另一个是 MSMQ。 GoF 将此产品关系称为“家族”,重要的是要注意,在这种情况下,家族并不意味着类层次结构。

public class Client {
    private final AbstractFactory_MessageQueue factory;

    public Client(AbstractFactory_MessageQueue factory) {
        // The factory creates message queues either for Azure or MSMQ.
        // The client does not know which technology is used.
        this.factory = factory;
    }

    public void sendMessage() {
        //The client doesn't know whether the OutboundQueue is Azure or MSMQ.
        OutboundQueue out = factory.createProductA();
        out.sendMessage("Hello Abstract Factory!");
    }

    public String receiveMessage() {
        //The client doesn't know whether the ReplyQueue is Azure or MSMQ.
        ReplyQueue in = factory.createProductB();
        return in.receiveMessage();
    }
}

public interface AbstractFactory_MessageQueue {
    OutboundQueue createProductA();
    ReplyQueue createProductB();
}

public class ConcreteFactory_Azure implements AbstractFactory_MessageQueue {
    @Override
    public OutboundQueue createProductA() {
        return new AzureMessageQueue();
    }

    @Override
    public ReplyQueue createProductB() {
        return new AzureResponseMessageQueue();
    }
}

public class ConcreteFactory_Msmq implements AbstractFactory_MessageQueue {
    @Override
    public OutboundQueue createProductA() {
        return new MsmqMessageQueue();
    }

    @Override
    public ReplyQueue createProductB() {
        return new MsmqResponseMessageQueue();
    }
}

工厂方法

这里要掌握的最重要的一点是 ConcreteCreator 是客户端。换句话说,客户端是一个子类,它的父类定义了 factoryMethod()。这就是为什么我们说工厂方法是通过继承实现的。第二个关键点是要记住,工厂方法模式只不过是模板方法模式的一种特殊化。这两种模式共享相同的结构。它们只是目的不同。工厂方法是创造性的(它构建一些东西),而模板方法是行为性的(它计算一些东西)。最后,要注意的第三点是 Creator(父)类调用了自己的 factoryMethod()。如果我们从父类中删除 anOperation() ,只留下一个方法,它就不再是工厂方法模式。也就是说,Factory Method不能在父类中使用少于两个的方法来实现;一个必须调用另一个。

public abstract class Creator {
    public void anOperation() {
        Product p = factoryMethod();
        p.whatever();
    }

    protected abstract Product factoryMethod();
}

public class ConcreteCreator extends Creator {
    @Override
    protected Product factoryMethod() {
        return new ConcreteProduct();
    }
}

杂项。 & 各种工厂模式

请注意,尽管 GoF 定义了两种不同的工厂模式,但它们并不是唯一存在的工厂模式。它们甚至不一定是最常用的工厂模式。第三个著名的例子是来自 Effective Java 的 Josh Bloch 的静态工厂模式。 Head First Design Patterns 这本书包含了另一种他们称之为简单工厂的模式。

不要陷入假设每个工厂模式都必须与 GoF 中的一个匹配的陷阱。


基于良好示例的出色且非常清晰的答案,这是 IMO 本主题中最好的。
很好的解释。工厂方法 +1 必须调用其抽象工厂方法点。有了这一点,就很清楚了,但不理解这一点:如果我们有工厂方法没有被它自己调用,这意味着它将被其他一些组成它的类使用,并且它的子类将被注入,它变成了抽象工厂,如果抽象工厂方法必须像模板方法模式一样由工厂本身调用,则差异变得不那么明显
再来一个问号。 factoryMethod() 是否应该始终是“工厂方法”模式中的 protected 方法? (我想是的)
@YaroslavFedoruk,GoF 书籍允许使用 public 工厂方法,并且该方法甚至不必是 abstract;但关键是该方法是为继承而设计的,因此它不能(例如)是 staticfinal。我在这里创建了方法 protectedabstract 以突出显示(必需的)可扩展性。
@nits.kk,您可能对 related answer 感兴趣。
j
jaco0646

抽象工厂是创建相关产品的接口,但工厂方法只是一种方法。抽象工厂可以通过多种工厂方法来实现。

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


您已经发布了相同的答案 here。如果您觉得这个问题很相似,请将其标记为重复。
非常清楚。这应该被选为这个问题的答案。当前选择的答案有多余的解释。
图中的第二个标题应为“这两个可能是工厂方法”。没有看到实现,我们不知道它们是否遵循工厂方法模式。一个常见的误解是抽象工厂的方法自动成为工厂方法。这不是真的。有两种不同的 GoF 模式是有原因的:它们的实现方式不同。
这确实有助于我掌握它,并且它类似于我在书中看到的示例。它仍然让我很不确定为什么我会这样做。但这不是问题...
A
Abdul Munim

考虑这个例子以便于理解。

电信公司提供什么?例如,宽带、电话线和移动电话,您被要求创建一个应用程序来向他们的客户提供他们的产品。

一般来说,您在这里要做的是,通过您的工厂方法创建产品,例如宽带、电话线和移动设备,您知道这些产品的属性,而且非常简单。

现在,该公司想为他们的客户提供一揽子产品,即宽带、电话线和移动设备,而抽象工厂就来了。

换句话说,抽象工厂是负责创造自己产品的其他工厂的组合,抽象工厂知道如何将这些产品放在更有意义的地方,就其自身的职责而言。

在这种情况下,BundleFactory 是抽象工厂,BroadbandFactoryPhonelineFactoryMobileFactoryFactory。为了进一步简化,这些工厂将有 Factory Method 来初始化各个产品。

请参阅下面的代码示例:

public class BroadbandFactory : IFactory {
    public static Broadband CreateStandardInstance() {
        // broadband product creation logic goes here
    }
}

public class PhonelineFactory : IFactory {
    public static Phoneline CreateStandardInstance() {
        // phoneline product creation logic goes here
    }
}

public class MobileFactory : IFactory {
    public static Mobile CreateStandardInstance() {
        // mobile product creation logic goes here
    }
}

public class BundleFactory : IAbstractFactory {

    public static Bundle CreateBundle() {
        broadband = BroadbandFactory.CreateStandardInstance();
        phoneline = PhonelineFactory.CreateStandardInstance();
        mobile = MobileFactory.CreateStandardInstance();

        applySomeDiscountOrWhatever(broadband, phoneline, mobile);
    }

    private static void applySomeDiscountOrWhatever(Broadband bb, Phoneline pl, Mobile m) {
        // some logic here
        // maybe manange some variables and invoke some other methods/services/etc.
    }
}

希望这可以帮助。


两种 GoF 工厂模式中都没有 static 方法。这是错误的。
R
Robson

工厂方法依赖于继承:对象的创建被委托给子类,子类实现工厂方法来创建对象。

抽象工厂依赖于对象组合:对象创建是在工厂接口中公开的方法中实现的。

工厂和抽象工厂模式的高级图,

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

有关 Factory 方法的更多信息,请参阅 this article

有关抽象工厂方法的更多信息,请参阅this article


V
Vikram Babu Nagineni

现实生活中的例子。 (容易记住)

工厂

想象一下,你正在建造一所房子,你找一个木匠找一扇门。你给出门的尺寸和你的要求,他会为你建造一扇门。在这种情况下,木匠是门的工厂。您的规格是工厂的输入,门是工厂的输出或产品。

抽象工厂

现在,考虑门的相同示例。你可以去木匠那里,也可以去塑料门店或PVC店。他们都是门厂。根据情况,你决定你需要接近什么样的工厂。这就像一个抽象工厂。

我在这里解释了工厂方法模式和抽象工厂模式,从不使用它们开始解释问题,然后使用上述模式解决问题https://github.com/vikramnagineni/Design-Patterns/tree/master


这是不正确的。这是一个非常普遍的误解,即抽象工厂只不过是工厂的工厂。
K
KGhatak

了解动机的差异:

假设您正在构建一个工具,其中包含对象和对象相互关系的具体实现。由于您预见到对象的变化,因此您通过将创建对象变体的责任分配给另一个对象(我们称之为抽象工厂)来创建间接。由于您预见到未来的扩展需要这些对象的变体,因此这种抽象具有很大的好处。

在这种思路中,另一个相当有趣的动机是整个组中的每个对象都有相应的变体。根据某些条件,将使用任一变体,并且在每种情况下,所有对象都必须具有相同的变体。这可能有点违反直觉,因为我们通常倾向于认为 - 只要对象的变体遵循共同的统一合同(更广泛意义上的接口),具体的实现代码就永远不会中断。这里有趣的事实是,并非总是如此,尤其是当预期行为无法通过编程合同建模时。

一个简单的(借用 GoF 的想法)是任何 GUI 应用程序,例如模拟 MS 或 Mac 或 Fedora OS 的外观的虚拟监视器。例如,当窗口、按钮等所有小部件对象都具有 MS 变体时,除了从 MAC 变体派生的滚动条之外,该工具的用途严重失败。

以上这些情况构成了抽象工厂模式的基本需求。

另一方面,假设您正在编写一个框架,以便许多人可以使用您的框架构建各种工具(例如上面示例中的工具)。通过框架的想法,你不需要,尽管你不能在你的逻辑中使用具体的对象。您宁愿在各种对象之间放置一些高级合约以及它们如何交互。虽然您(作为框架开发人员)仍处于非常抽象的级别,但该工具的每个构建者都被迫遵循您的框架结构。但是,他们(工具构建者)可以自由决定要构建什么对象以及他们创建的所有对象将如何交互。与前一种情况(抽象工厂模式)不同,您(作为框架创建者)在这种情况下不需要使用具体对象;而是可以停留在对象的合同级别。此外,与前面动机的第二部分不同,您或工具构建者永远不会遇到混合来自变体的对象的情况。在这里,虽然框架代码仍处于合同级别,但每个工具构建者都被限制(根据案例本身的性质)使用自己的对象。在这种情况下,对象创建被委托给每个实现者,框架提供者只提供创建和返回对象的统一方法。这样的方法对于框架开发者来说是不可避免的继续他们的代码,并且有一个特殊的名字叫做工厂方法(工厂方法模式为底层模式)。

几点注意事项:

如果您熟悉“模板方法”,那么您会看到工厂方法通常是从模板方法调用的,以防与任何形式的框架有关的程序。相比之下,应用程序的模板方法通常是特定算法的简单实现,没有工厂方法。

此外,为了思想的完整性,使用框架(上面提到的),当工具构建者在构建工具时,在每个工厂方法内部,他/她可能会进一步将责任委托给抽象对象,而不是创建具体的对象-factory 对象,前提是工具构建器可以预见未来扩展的具体对象的变化。

示例代码:

//Part of framework-code
BoardGame {
    Board createBoard() //factory method. Default implementation can be provided as well
    Piece createPiece() //factory method

    startGame(){        //template method
         Board borad = createBoard()
         Piece piece = createPiece()
         initState(board, piece)
    }
}


//Part of Tool-builder code
Ludo inherits  BoardGame {
     Board createBoard(){ //overriding of factory method
         //Option A: return new LudoBoard() //Lodu knows object creation
         //Option B: return LudoFactory.createBoard() //Lodu asks AbstractFacory
     }
….
}

//Part of Tool-builder code
Chess inherits  BoardGame {
    Board createBoard(){ //overriding of factory method
        //return a Chess board
    }
    ….
}

R
Ravindra babu

我的第一个问题是关于抽象工厂的。它的作用是允许您在其中创建具体对象系列(这可能取决于您使用的特定工厂),而不仅仅是单个具体对象?

是的。抽象工厂的意图是:

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

抽象工厂是否只返回一个非常大的对象或许多对象,具体取决于您调用的方法?

理想情况下,它应该为每个客户端调用的方法返回一个对象。

我的理解是工厂方法模式有一个 Creator 接口,这将使 ConcreteCreator 负责知道要实例化哪个 ConcreteProduct。这就是使用继承来处理对象实例化的意思吗?

是的。工厂方法使用继承。

抽象工厂模式通过组合将对象实例化的责任委托给另一个对象?这是什么意思?

AbstractFactory 定义了一个 FactoryMethod,而 ConcreteFactory 负责构建一个 ConcreteProduct。只需按照此 article 中的代码示例进行操作即可。

您可以在相关的 SE 帖子中找到更多详细信息:

What is the basic difference between the Factory and Abstract Factory Patterns?

Design Patterns: Factory vs Factory method vs Abstract Factory


A
Anand

那里有很多定义。基本上,描述工厂模式的三种常用方式是

简单工厂

基于条件的简单对象创建方法/类。

工厂方法

工厂方法设计模式使用子类来提供实现。

抽象工厂

抽象工厂设计模式在不指定具体类的情况下生成相关或依赖对象的系列。

以下链接非常有用 - Factory Comparison - refactoring.guru


A
Adrian Liu

让我们明确一点,在生产代码的大部分时间里,我们使用抽象工厂模式,因为类 A 是用接口 B 编程的。A 需要创建 B 的实例。所以 A 必须有一个工厂对象来生成 B 的实例.所以A不依赖于B的任何具体实例。希望它有所帮助。


S
Saurabh

为了使界面变得非常简单,请关注“//1”:

class FactoryProgram
    {
        static void Main()
        {
            object myType = Program.MyFactory("byte");
            Console.WriteLine(myType.GetType().Name);

            myType = Program.MyFactory("float"); //3
            Console.WriteLine(myType.GetType().Name);

            Console.ReadKey();
        }

        static object MyFactory(string typeName)
        {
            object desiredType = null; //1
            switch (typeName)
            {
                case "byte": desiredType = new System.Byte(); break; //2
                case "long": desiredType = new System.Int64(); break;
                case "float": desiredType = new System.Single(); break;
                default: throw new System.NotImplementedException();
            }
            return desiredType;
        }
    }

这里重点: 1. Factory & AbstractFactory 机制必须使用继承(System.Object-> byte, float ...);因此,如果您在程序中有继承,那么工厂(抽象工厂很可能不会存在)在设计上已经存在 2. Creator(MyFactory)知道具体类型,因此将具体类型对象返回给调用者(Main);在抽象工厂返回类型将是一个接口。

interface IVehicle { string VehicleName { get; set; } }
interface IVehicleFactory
    {
        IVehicle CreateSingleVehicle(string vehicleType);
    }
class HondaFactory : IVehicleFactory
    {
        public IVehicle CreateSingleVehicle(string vehicleType)
        {
            switch (vehicleType)
            {
                case "Sports": return new SportsBike();
                case "Regular":return new RegularBike();
                default: throw new ApplicationException(string.Format("Vehicle '{0}' cannot be created", vehicleType));
            }
        }
    }
class HeroFactory : IVehicleFactory
    {
        public IVehicle CreateSingleVehicle(string vehicleType)
        {
            switch (vehicleType)
            {
                case "Sports":  return new SportsBike();
                case "Scooty": return new Scooty();
                case "DarkHorse":return new DarkHorseBike();
                default: throw new ApplicationException(string.Format("Vehicle '{0}' cannot be created", vehicleType));
            }
        }
    }

class RegularBike : IVehicle { public string VehicleName { get { return "Regular Bike- Name"; } set { VehicleName = value; } } }
class SportsBike : IVehicle { public string VehicleName { get { return "Sports Bike- Name"; } set { VehicleName = value; } } }
class RegularScooter : IVehicle { public string VehicleName { get { return "Regular Scooter- Name"; } set { VehicleName = value; } } }
class Scooty : IVehicle { public string VehicleName { get { return "Scooty- Name"; } set { VehicleName = value; } } }
class DarkHorseBike : IVehicle { public string VehicleName { get { return "DarkHorse Bike- Name"; } set { VehicleName = value; } } }

class Program
{
    static void Main(string[] args)
    {
        IVehicleFactory honda = new HondaFactory(); //1
        RegularBike hondaRegularBike = (RegularBike)honda.CreateSingleVehicle("Regular"); //2
        SportsBike hondaSportsBike = (SportsBike)honda.CreateSingleVehicle("Sports");
        Console.WriteLine("******* Honda **********"+hondaRegularBike.VehicleName+ hondaSportsBike.VehicleName);

        IVehicleFactory hero = new HeroFactory();
        DarkHorseBike heroDarkHorseBike = (DarkHorseBike)hero.CreateSingleVehicle("DarkHorse");
        SportsBike heroSportsBike = (SportsBike)hero.CreateSingleVehicle("Sports");
        Scooty heroScooty = (Scooty)hero.CreateSingleVehicle("Scooty");
        Console.WriteLine("******* Hero **********"+heroDarkHorseBike.VehicleName + heroScooty.VehicleName+ heroSportsBike.VehicleName);

        Console.ReadKey();
    }
}

要点: 1. 要求:Honda 会创建“Regular”、“Sports”,而 Hero 会创建“DarkHorse”、“Sports”和“Scooty”。 2. 为什么有两个接口?一个用于制造商类型(IVehicleFactory),另一个用于产品工厂(IVehicle);理解 2 个接口的另一种方式是抽象工厂是关于创建相关对象 2。关键是 IVehicleFactory 的孩子返回和 IVehicle(而不是工厂中的具体);所以我得到父变量(IVehicle);然后我通过调用 CreateSingleVehicle 创建实际的具体类型,然后将父对象转换为实际的子对象。如果我做 RegularBike heroRegularBike = (RegularBike)hero.CreateSingleVehicle("Regular"); 会发生什么;你会得到 ApplicationException 这就是为什么我们需要通用抽象工厂,如果需要我会解释。希望它对初学者和中级观众有所帮助。


I
Islam Alshnawey

A) 工厂方法模式

工厂方法是一种创建型设计模式,它提供了一个用于创建对象的接口,但允许子类更改将要创建的对象的类型。

如果您在基类和扩展它的子类中有创建方法,您可能正在查看工厂方法。

B) 抽象工厂模式

抽象工厂是一种创建设计模式,它允许在不指定具体类的情况下生成相关或依赖对象的系列。

什么是“对象族”?例如,采用这组类:Transport + Engine + Controls。这些可能有几种变体:

1- 汽车 + CombustionEngine + SteeringWheel

2- 飞机 + 喷气发动机 + 轭

如果您的程序不与产品系列一起运行,那么您不需要抽象工厂。

同样,很多人将抽象工厂模式与声明为抽象的简单工厂类混为一谈。不要那样做!

参考:https://refactoring.guru/design-patterns/factory-comparison


A
Andy2K11

据我估计,@TomDalling 给出的答案确实是正确的(就其价值而言),但是评论中似乎仍然存在很多混乱。

我在这里所做的是为这两种模式创建了一些稍微不典型的示例,并试图使它们乍一看非常相似。这将有助于查明将它们分开的关键差异。

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

如果您对这些模式完全陌生,那么这些示例可能不是最好的起点。

工厂方法

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

客户端.javaish

Client(Creator creator) {
    ProductA a = creator.createProductA();
}

Creator.javaish

Creator() {}

void creatorStuff() {
    ProductA a = createProductA();
    a.doSomething();
    ProductB b = createProductB();
    b.doStuff();
}

abstract ProductA createProductA();

ProductB createProductB() {
    return new ProductB1();
}

为什么会有创作者和客户?

为什么不? FactoryMethod 可以与这两者一起使用,但它将是 Creator 的类型来确定所创建的特定产品。

为什么 Creator 中没有 createProductB 抽象?

可以提供默认实现,子类仍然可以覆盖该方法以提供自己的实现。

我认为工厂方法只能创建一种产品?

每个方法确实只返回一个产品,但创建者可以使用多个工厂方法,它们不一定以任何特定方式相关。

抽象工厂

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

客户端.javaish

AbstractFactory factory;

Client() {
    if (MONDAY) {
        factory = new Factory2();
    } else {
        factory = new AbstractFactory();
    }
}

void clientStuff() {
    ProductA a = factory.createProductA();
    a.doSomething();
    ProductB b = factory.createProductB();
    b.doStuff();
}

等待!你的 AbstractFactory 不是,嗯……呃 Abstract

没关系,我们仍然提供接口。 create 方法的返回类型是我们想要制作的产品的超类型。

圣烟蝙蝠侠! Factory2 没有覆盖 createProductA(),“产品系列”发生了什么?

模式中没有任何内容表明一个对象不能属于多个系列(尽管您的用例可能会禁止它)。每个混凝土工厂负责决定允许一起创建哪些产品。

这不可能,客户端没有使用依赖注入

您必须决定您的具体类将在某个地方,Client 仍然写入 AbstractFactory 接口。

这里的混淆在于人们将 compositiondependency injection 混为一谈。 Client HAS-A AbstractFactory,不管它是如何获得的。与 IS-A 关系相比,ClientAbstractFactory 之间没有继承关系。

主要区别

抽象工厂总是关于对象家族

工厂方法只是一种允许子类指定具体对象类型的方法

抽象工厂为客户端提供了一个接口,并且与使用产品的地方是分开的,工厂方法可以由创建者自己使用或暴露给客户端。

概括

工厂的目的是向客户或自身提供对象。

创建者有自己的职责,可能需要使用对象或将它们传递给客户端

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

仅抽象工厂:

提供[s] 一个接口,用于创建相关或依赖对象的系列,而无需指定它们的具体类。 - GoF

如果您想使用图表,请使用 PlantUML 代码:

@startuml FactoryMethod
abstract class Creator {
    creatorStuff()
    {abstract} createProductA(): ProductA
    createProductB(): ProductB
}
class Creator1 {
    createProductA(): ProductA
}
class Creator2 {
    createProductA(): ProductA
    createProductB(): ProductB
}

together {
    interface ProductA {
        doSomething()
    }
    class ProductA1
    ' class Product1B
}
together {
    interface ProductB {
        doStuff()
    }
    class ProductB1
    class ProductB2
}
Client --> Creator

Creator <|-- Creator1
Creator <|-- Creator2

Creator --> ProductB1
ProductA1 <-- Creator1
ProductA1 <-- Creator2
ProductB2 <-- Creator2

ProductA <|.. ProductA1
ProductB <|.. ProductB1
ProductB <|.. ProductB2

ProductA <- Creator

@enduml
@startuml AbstractFactory

together {
    interface ProductA {
        doSomething()
    }
    class ProductA1
}

together {
    interface ProductB {
        doStuff()
    }
    class ProductB1
    class ProductB2
}

class AbstractFactory {
    createProductA(): ProductA
    createProductB(): ProductB
    --
    -
}

class Factory2 {
    createProductB(): ProductB
}

Client --> AbstractFactory
AbstractFactory <|-- Factory2

ProductA <|.. ProductA1
ProductB <|.. ProductB1
ProductB <|.. ProductB2

AbstractFactory --> ProductA1
AbstractFactory --> ProductB1
ProductB2 <-- Factory2

@enduml

为什么有Creator和Client?为什么不呢?”因为它得出的结论是每个方法都是工厂方法。工厂方法的一个常见误解是它们只不过是名为 create 的方法。第二个 Client 似乎证实了这一点;但在 Client 调用 create 中没有设计模式。 ObjectA 调用 ObjectB 来获取 ObjectC 是普通的、普通的 OOP。该模式是 Creator 是它自己的客户端。这发生在 creatorStuff() 中。这是一个有效的例子;但是多个客户端很容易错过模式的重点。
人们将组合与依赖注入混为一谈。”设计原则是组合+松耦合==依赖倒置。不推荐使用紧密耦合的组合模式,这就是为什么您不经常看到以这种方式描述的抽象工厂的原因。当然,Client 可以通过违反依赖倒置原则来获取实例,但是紧耦合的所有后果都随之而来。
y
yoAlex5

工厂设计模式

generation 1 <- generation 2 <- generation 3
//example
(generation 1) shape <- (generation 2) rectangle, oval <- (generation 3) rectangle impressionism, rectangle surrealism, oval impressionism, oval surrealism

工厂

用例:实例化 generation 2一个 对象

它是一种 Creational 模式,可让您在一个简单的地方创建 generation 2。它符合 SRP 和 OCP - 所有更改都在一个类中进行。

enum ShapeType {
    RECTANGLE,
    OVAL
}

class Shape {}

//Concrete Products
//generation 2
class Rectangle extends Shape {}
class Oval extends Shape {}

//Factory
class Factory {
    Shape createShape(ShapeType type) {

        switch (type) {
            case RECTANGLE:
                return new Rectangle();
            case OVAL:
                return new Oval();
        }
    }
}

//Creator
class Painter {

    private Factory factory;

    Painter(Factory factory) {
        this.factory = factory;
    }

    Shape prepareShape(ShapeType type) {
        return factory.createShape(type);
    }
}

//using
class Main {
    void main() {
        Painter painter = new Painter(new Factory());

        Shape shape1 = painter.prepareShape(ShapeType.RECTANGLE);
        Shape shape2 = painter.prepareShape(ShapeType.OVAL);
    }
}

工厂方法

用例:实例化 generation 3一个 对象

有助于与下一代家庭成员一起工作。每个画家都有自己的风格,如印象派、超现实主义……Factory Method 使用抽象 Creator 作为工厂(抽象方法),Concrete Creators 是这种方法的实现

enum ShapeType {
    RECTANGLE,
    OVAL
}

class Shape {}

//Concrete Products
//generation 2
class Rectangle extends Shape {}
class Oval extends Shape {}

//generation 3
class RectangleImpressionism extends Rectangle {}
class OvalImpressionism extends Oval {}
class RectangleSurrealism extends Rectangle {}
class OvalSurrealism extends Oval {}

//Creator
abstract class Painter {

    Shape prepareShape(ShapeType type) {
        return createShape(type);
    }

    //Factory method
    abstract Shape createShape(ShapeType type);
}

//Concrete Creators
class PainterImpressionism {

    @override
    Shape createShape(ShapeType type) {
        switch (type) {
            case RECTANGLE:
                return new RectangleImpressionism();
            case OVAL:
                return new OvalImpressionism();
        }
    }
}

class PainterSurrealism {

    @override
    Shape createShape(ShapeType type) {
        switch (type) {
            case RECTANGLE:
                return new RectangleSurrealism();
            case OVAL:
                return new OvalSurrealism();
        }
    }
}

//using
class Main {
    void main() {
        Painter painterImpressionism = new PainterImpressionism();
        Shape shape1 = painterImpressionism.prepareShape(ShapeType.RECTANGLE);

        Painter painterSurrealism = new PainterSurrealism();
        Shape shape2 = painterSurrealism.prepareShape(ShapeType.RECTANGLE);
    }
}

抽象工厂

用例:实例化 generation 3所有 对象

Factory 是抽象 Factory 的一部分,在 Concrete Factories 中实现


//Concrete Products
//generation 2
class Rectangle extends Shape {}
class Oval extends Shape {}

//generation 3
class RectangleImpressionism extends Rectangle {}
class OvalImpressionism extends Oval {}
class RectangleSurrealism extends Rectangle {}
class OvalSurrealism extends Oval {}

//Abstract Factory
interface Factory {
    Rectangle createRectangle();
    Oval createOval();
}

//Concrete Factories
class ImpressionismFactory implements Factory {
    @Override
    public Rectangle createRectangle() {
        return new RectangleImpressionism();
    }

    @Override
    public Oval createOval() {
        return new OvalImpressionism();
    }
}

class SurrealismFactory implements Factory {
    @Override
    public Rectangle createRectangle() {
        return new RectangleSurrealism();
    }

    @Override
    public Oval createOval() {
        return new OvalSurrealism();
    }
}

//Creator
class Painter {

    Rectangle rectangle;
    Oval oval;

    Painter(Factory factory) {
        rectangle = factory.createRectangle();
        rectangle.resize();

        oval = factory.createOval();
        oval.resize();
    }
}

//using
class Main {
    void main() {
        Painter painter1 = new Painter(new ImpressionismFactory());
        Shape shape1 = painter1.rectangle;
        Shape shape2 = painter1.oval;

        Painter painter2 = new Painter(new ImpressionismFactory());
        Shape shape3 = painter2.rectangle;
        Shape shape4 = painter1.oval;
    }
}

h
he9lin

任何时候我都喜欢抽象工厂而不是工厂方法。从上面 Tom Dalling 的示例(顺便说一句很好的解释)中,我们可以看到抽象工厂更具可组合性,因为我们需要做的就是将不同的工厂传递给构造函数(此处使用构造函数依赖注入)。但是工厂方法要求我们引入一个新的类(要管理的东西更多)并使用子类化。总是更喜欢组合而不是继承。


A
Atul Jain

抽象工厂:工厂的工厂;将单个但相关/依赖的工厂组合在一起而不指定它们的具体类的工厂。 Abstract Factory Example

Factory:它提供了一种将实例化逻辑委托给子类的方法。 Factory Pattern Example


这是不正确的。这是一个非常普遍的误解,即抽象工厂只不过是工厂的工厂。
P
Peter Mortensen

请允许我准确地说。大多数答案已经解释过,还提供了图表和示例。

所以我的回答只是一个单行字。我自己的话:“抽象工厂模式在多个工厂方法实现上添加了抽象层。这意味着一个抽象工厂包含或组合一个或多个工厂方法模式”


这是不正确的。这是一个非常普遍的误解,即抽象工厂只不过是工厂的工厂。
P
Peter Mortensen

很多以前的答案都没有提供抽象工厂和工厂方法模式之间的代码比较。以下是我尝试通过 Java 来解释它。我希望它可以帮助需要简单解释的人。

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

public class Client {
    public static void main(String[] args) {
        ZooFactory zooFactory = new HerbivoreZooFactory();
        Animal animal1 = zooFactory.animal1();
        Animal animal2 = zooFactory.animal2();
        animal1.sound();
        animal2.sound();

        System.out.println();

        AnimalFactory animalFactory = new CowAnimalFactory();
        Animal animal = animalFactory.createAnimal();
        animal.sound();
    }
}

public interface Animal {
    public void sound();
}

public class Cow implements Animal {

    @Override
    public void sound() {
        System.out.println("Cow moos");
    }
}

public class Deer implements Animal {

    @Override
    public void sound() {
        System.out.println("Deer grunts");
    }

}

public class Hyena implements Animal {

    @Override
    public void sound() {
        System.out.println("Hyena.java");
    }

}

public class Lion implements Animal {

    @Override
    public void sound() {
        System.out.println("Lion roars");
    }

}

public interface ZooFactory {
    Animal animal1();

    Animal animal2();
}

public class CarnivoreZooFactory implements ZooFactory {

    @Override
    public Animal animal1() {
        return new Lion();
    }

    @Override
    public Animal animal2() {
        return new Hyena();
    }

}

public class HerbivoreZooFactory implements ZooFactory {

    @Override
    public Animal animal1() {
        return new Cow();
    }

    @Override
    public Animal animal2() {
        return new Deer();
    }

}

public interface AnimalFactory {
    public Animal createAnimal();
}

public class CowAnimalFactory implements AnimalFactory {

    @Override
    public Animal createAnimal() {
        return new Cow();
    }

}

public class DeerAnimalFactory implements AnimalFactory {

    @Override
    public Animal createAnimal() {
        return new Deer();
    }

}

public class HyenaAnimalFactory implements AnimalFactory {

    @Override
    public Animal createAnimal() {
        return new Hyena();
    }

}

public class LionAnimalFactory implements AnimalFactory {

    @Override
    public Animal createAnimal() {
        return new Lion();
    }

}

这是不正确的。这段代码实现了一个非常普遍的误解,即抽象工厂只不过是工厂的工厂。
@jaco0646 我相信在工厂方法模式中,重点是从 FactoryImpl 中获取一个具体的产品。而在抽象工厂模式中,FactoryImpls 负责提供多个相似/相关的 ConcreteProducts,Factory 接口为此提供了一个契约。所以 ZooFactory 根本不是你所说的工厂工厂,而只是一个接口,其 Impls 提供相互关联的具体产品。如果您不同意,请随时纠正我的理解。
在工厂方法中,重点是通过子类继承,因为工厂方法是模板方法模式的一种特殊形式。上面投票最多的答案显示了一个不错的代码示例。
@jaco0646 1. 这是否意味着在上面的示例中,我不应该使用 AnimalFactory 的接口并提供其实现,而应该使用一个类并在其子类中重写 createAnimal() 方法:CowAnimalFactory、LionAnimalFactory 等?? 2. 另外,你对 ZooFactory 的例子有什么看法?
对于第一个问题:是的。其次,我在这个线程中添加了我自己的答案,而不是继续批评每个单独的答案。
D
DSK

带有实时示例的抽象工厂设计模式:什么是抽象工厂设计模式?它类似于工厂方法设计模式。当我们有多个工厂时,我们需要使用这种模式。此模式中将定义一组工厂。工厂方法模式是抽象工厂设计模式的一个子集。它们具有与工厂模式相同的优点。抽象工厂依赖于对象组合,而工厂方法处理继承。 java中的工厂设计模式与实时示例:什么是工厂设计模式?它主要用于面向对象编程中的设计。它是创造模式之一。这都是关于创建实例的。客户端将创建对象而不暴露于对象创建逻辑。它广泛用于不同的框架,例如:spring 框架。当类不知道它必须创建的另一个对象时,我们使用这种模式。实时示例:当我们的汽车在路上抛锚时。我们需要告知修理工我们使用的是什么类型的车辆,以便修理工携带工具进行修理。根据我们的意见,修理工将解决问题并为我们再次旅行做好准备。有一些使用这些模式的内置方法。 JavaUtilcalendar 类中的示例 getInstance() 方法。在 getInstance() 的帮助下,我们可以在执行此方法时获取对象。 Javautilcalendar : getInstance() 是方法返回对象。 https://trendydevx.com/factory-design-pattern-in-java-with-realtime-example/


M
Moshe

我的结论是:没有区别。为什么?因为我看不出用工厂方法为工厂以外的对象配备任何理由 - 否则你会违反责任分离原则。此外,我看不出具有单个工厂方法的工厂和具有多个工厂方法的工厂之间有什么区别:两者都创建“相关对象的家庭”,除非有人能证明单一家庭成员的家庭不是家庭。或者包含单个项目的集合不是集合。