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


454

我知道有很多关于这两种模式之间差异的文章,但是有些事情我找不到。

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

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

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

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

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

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



从客户端的角度看“实例如何创建”,将有助于您理解报价。
Karthik Bose

@nawfal,该线程中的答案太糟糕了。
jaco0646 '16

Answers:


494

两者之间的区别

“工厂方法”与“抽象工厂”之间的主要区别在于工厂方法是单一方法,而抽象工厂是对象。我认为很多人将这两个术语弄混了,并开始互换使用。我记得当我学习它们时,我很难找到确切的区别。

因为factory方法只是一个方法,所以可以在子类中覆盖它,因此引号的后半部分:

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

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

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

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

他们在说的是,有一个对象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

15
这是一个很好的解释。但是,最重要的部分仍然没有答案,那就是:何时使用一种模式,何时使用另一种模式?
croraf 2014年

11
不确定这是正确的。可以肯定,Factory Method是一种工厂方法命名的设计模式,但是涉及类结构和继承。这不是一个单一的方法。
阿维夫·科恩

2
这么说是正确的:Factory方法可以是所有具有不同用途的常规类中的方法。但是抽象工厂是客户使用的类/对象,仅负责在一个家庭中创建某些产品吗?
Hieu Nguyen 2014年

您在“ SuperFoo”中使用“ Super”一词仅是为了表示Foo的特例,还是实际上意味着超类?正如我假设的那样,它必须是子类。
dahui

@dahui是的,它是一个子类。我将其更改SpecialFoo为更加清楚。
Tom Dalling

125

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

在此处输入图片说明

工厂方法只是用于在类中创建对象的简单方法。通常将其添加到聚合根中(Order该类的方法称为CreateOrderLine

在此处输入图片说明

抽象工厂

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

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替换原理)。


3
为什么我们需要混凝土产品?
Andrew S

60
因为没有人愿意投资于想法。
jgauffin

4
抽象工厂不仅应创建Button()“相关产品系列”,还应创建更多产品。例如,规范的GoF示例创建ScrollBar()Window()。这样做的好处是,抽象工厂可以在其多个产品中实施一个通用主题。
jaco0646 '16

哈科是对的。考虑两个UML图本质上是相同的(除了Abstract Factory UML错误)。在这两种情况下,客户都调用一种工厂方法来创建一个单一产品。
cobby

1
@AndrewS:回答您的问题。如果我们不需要为相同的抽象(接口)使用不同的具体产品(类),则可能需要使用构建器模式而不是工厂模式。(迟到总比不到好;))
jgauffin

95

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

  • 工厂方法仅用于创建一种产品,而抽象工厂相关或从属产品系列。
  • 工厂方法模式向客户端公开了一种用于创建对象的方法,而对于抽象工厂而言它们公开了一系列可能由这些Factory方法组成的相关对象。
  • 工厂方法模式隐藏单个对象的构造,而抽象工厂隐藏了一系列相关对象的构造。抽象工厂通常使用一组工厂方法来实现。
  • 抽象工厂模式使用合成将创建对象的责任委托给其他方法,工厂方法设计模式使用继承并依赖于派生的类或子类来创建对象。
  • Factory Method模式背后的想法是,它允许以下情况:客户端不知道在运行时需要创建哪些具体类,而只是想获得一个在Abstract Factory 模式下可以完成工作的类当您的系统必须创建多个产品系列,或者您想提供一个产品库而又不暴露实现细节时,可以最好地利用它!

工厂方法模式实现: 工厂方法UML

抽象工厂模式实现:

UML抽象工厂


13
嗯,不确定抽象工厂示例。我认为形状工厂和颜色工厂应该实现相同的方法。但是,如果我是对的,那么样本是没有意义的。
Joaquin Iurchuk

4
要点是正确的。但是,这两个图都是完全错误的并且非常容易误导。有关抽象工厂的准确模型,请参见@Trying下图。
jaco0646 '16

1
我必须同意这2个图确实确实具有误导性。我已经在tutorialspoint网站上看​​到了它们,说实话,我不是100%同意它们。尽管描述看起来不错
SoftwareDeveloper

这是非常误导的。
diyoda_

超过50次投票,图表非常错误。证明您不能相信SO上的许多设计模式答案。
Fuhrmanator

27

抽象工厂与工厂方法的主要区别在于抽象工厂是通过组合实现的 ; 但是Factory方法是通过Inheritance实现的

是的,您没看错:这两种模式之间的主要区别是旧的组合与继承之争。

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

抽象工厂

  1. 这里要掌握的最重要的一点是,将抽象工厂注入到客户端中。这就是为什么我们说Abstract Factory是由Composition实现的。通常,依赖项注入框架将执行该任务。但是DI不需要框架。
  2. 第二个关键点是这里的混凝土工厂不是工厂方法实现!下面进一步显示了工厂方法的示例代码。
  3. 最后,要注意的第三点是产品之间的关系:在这种情况下,出站和答复队列。一个具体的工厂产生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();
    }
}

工厂方法

  1. 这里要把握的最重要一点ConcreteCreator 客户。换句话说,客户端是其父级定义的子类factoryMethod()。这就是为什么我们说工厂方法是通过继承实现的。
  2. 第二个关键点是要记住,工厂方法模式不过是模板方法模式的一种特殊化。这两种模式共享相同的结构。他们只是目的不同。Factory Method是创造性的(它构建一些东西),而Template Method是行为性的(它计算一些东西)。
  3. 最后,要注意的第三点是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定义了两个不同的Factory模式,但它们并不是唯一存在的Factory模式。它们甚至不一定是最常用的Factory模式。第三个著名的例子是来自有效Java的Josh Bloch的Static Factory Pattern。《 Head First设计模式》一书包括了另一个称为“简单工厂”的模式。

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


3
基于很好的例子,这是IMO最好的例子,答案非常清楚。
卢克·杜达

很好的解释。工厂方法的+1必须调用其抽象工厂方法点。关于这一点,很清楚,没有理解这一点:如果我们没有调用工厂方法,则它自身暗示它将被构成它的其他一些类使用,并将其子类注入,它将变成抽象工厂,如果无法理解工厂必须像工厂模板方法模式那样调用抽象工厂方法的话,区别就不太清楚了
nits.kk

再问一个问题。应该factoryMethod()始终是protected “工厂方法”模式中的方法吗?(我认为是)
Yaroslav Fedoruk

1
@ YaroslavFedoruk,GoF书中允许使用public工厂方法,而该方法甚至不需要abstract;但关键点在于该方法旨在继承,因此(例如)不能为staticfinal。我已经提出了方法protectedabstract这里重点介绍了(必需的)可扩展性。
jaco0646'9

@ nits.kk,您可能对相关的答案感兴趣。
jaco0646 '19

26

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

UML抽象工厂


10
您已经在此处发布了相同的答案。如果您认为此问题相似,请将其标记为重复。
杰克

11

考虑此示例,以便于理解。

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

通常,您在这里要做的就是通过工厂方法来创建宽带,电话线和移动电话等产品在此您可以知道这些产品具有哪些属性,而且非常简单。

现在,该公司希望向其客户提供其捆绑的产品,即宽带,电话线和移动设备,而“ 抽象工厂”就在这里。

换句话说,抽象工厂是负责创建自己的产品的其他工厂的组成,抽象工厂知道如何根据自己的职责将这些产品置于更有意义的位置。

在这种情况下,BundleFactory是抽象工厂,BroadbandFactoryPhonelineFactoryMobileFactoryFactory。为简化起见,这些工厂将使用工厂方法来初始化各个产品。

Se下面的代码示例:

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.
    }
}

希望这可以帮助。


1
static在任何一种GoF工厂模式中都没有方法。错了
jaco0646 '19

5

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

想象一下,您正在盖房子,然后接近木匠的门。您对门和您的要求进行测量,他会为您建造一扇门。在这种情况下,木匠是门的工厂。您的规格是工厂的输入,门是工厂的输出或产品。

抽象工厂

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

我在这里已经解释了Factory方法模式和抽象工厂模式,首先不使用它们来解释问题,然后通过使用上述模式来解决问题 https://github.com/vikramnagineni/Design-Patterns/tree/master


3

让我们明确指出,在生产代码中的大多数时间里,我们使用抽象工厂模式,因为类A是使用接口B编程的。并且A需要创建B的实例。因此,A必须具有工厂对象才能产生B的实例。因此,A并不依赖于B的任何具体实例。


3

了解动机上的差异:

假设您正在建立一个放置对象的工具,并具体实现了对象之间的相互关系。由于您已预见到对象的变化,因此已经通过将创建对象的变化的责任分配给另一个对象(我们称为抽象工厂)来创建了间接方法。)。因为您可以预见将来的扩展需要这些对象的变体,所以这种抽象有很大的好处。

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

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

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

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

一些注意事项:

  • 如果您熟悉“模板方法”,那么您会发现,如果程序与任何形式的框架有关,则通常会从模板方法中调用工厂方法。相比之下,应用程序的模板方法通常是特定算法的简单实现,并且没有工厂方法。
  • 此外,为了使思想完整,使用框架(如上所述),当工具构建者在每个工厂方法内部构建工具时,可以创建一个抽象对象,而不是创建一个具体对象,而是将责任进一步委托给一个抽象对象。工厂对象,提供给工具构建者预见的具体对象的变体,以备将来扩展。

样例代码:

//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
    }
    ….
}

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

是。抽象工厂的意图是:

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


  1. 抽象工厂是否仅根据调用的方法返回一个很大的对象或一个很大的对象?

理想情况下,它应在方法客户端每次调用时返回一个对象。

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

是。工厂方法使用继承。

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

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

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

工厂模式和抽象工厂模式之间的基本区别是什么?

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


3

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

摘要工厂依赖于对象组成:对象创建是通过工厂接口中公开的方法实现的。

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

图

有关Factory方法的更多信息,请参考本文

有关抽象工厂方法的更多信息,请参考本文


2

要使用最少的界面使其变得非常简单,请关注“ // 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 ...);因此,如果您在程序中具有继承关系,则设计时就已经存在Factory(很可能不存在Abstract Factory)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.要求:本田将创建“ Regular”,“ Sports”,但Hero将创建“ DarkHorse”,“ Sports”和“ Scooty”。2.为什么要两个接口?一个用于制造商类型(IVehicleFactory),另一个用于产品工厂(IVehicle);理解2接口的另一种方法是抽象工厂,所有关于创建相关对象2的问题是IVehicleFactory的子代返回和IVehicle(而不是工厂中的具体对象);所以我得到了父变量(IVehicle); 然后我通过调用CreateSingleVehicle创建实际的具体类型,然后将父对象转换为实际的子对象。如果我这样做会发生什么RegularBike heroRegularBike = (RegularBike)hero.CreateSingleVehicle("Regular");; 您将获得ApplicationException,这就是为什么我们需要通用的抽象工厂,如果需要的话,我会解释。



0

我会随时支持抽象工厂而不是工厂方法。从上面的Tom Dalling的示例(详细解释btw)中,我们可以看到Abstract Factory更可组合,因为我们需要做的就是将一个不同的Factory传递给构造函数(此处使用的构造函数依赖项注入)。但是Factory Method要求我们引入一个新类(要管理的更多事情)并使用子类化。总是喜欢使用组合而不是继承。


0

请允许我准确地说。大多数答案已经得到了解释,还提供了图表和示例。所以我的那只不过是一支班轮。我自己的话:- “抽象工厂模式在多个工厂方法实现的抽象层上添加了内容。表示抽象工厂包含或组合一个或多个工厂方法模式”


这是不正确的。这是一个非常普遍的误解,认为抽象工厂不过是工厂的工厂。
jaco0646

0

上面的许多答案都没有提供Abstract Factory模式和Factory Method模式之间的代码比较。以下是我尝试通过Java进行解释的尝试。希望它可以帮助需要简单解释的人。

正如GoF恰当地说的那样:Abstract Factory提供了一个接口,用于创建相关或依赖对象的族,而无需指定其具体类。

        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

1
@ jaco0646我相信在工厂方法模式中,重点是从FactoryImpl中仅获取一种具体产品。在抽象工厂模式下,FactoryImpls负责提供多个相似/相关的ConcreteProducts,而Factory接口则为其提供合同。因此,正如您所说,ZooFactory根本不是工厂的工厂,而只是一个接口,其Impls提供彼此相关的具体产品。如果您不同意,请随时纠正我的理解。
贾汀·沙舒

在Factory Method中,重点是通过子类进行继承,因为Factory Method是Template Method模式的特化。上面最受好评的答案显示了一个不错的代码示例。
jaco0646

@ jaco0646 1.这是否意味着在上面的示例中,我应该使用一个类并在其子类中覆盖方法createAnimal():CowAnimalFactory,LionAnimalFactory等,而不是为AnimalFactory使用接口并提供其实现??2.另外,您对ZooFactory显示的示例有何想法?
贾汀·沙舒

对于第一个问题:是的。在第二篇中,我在此主题中添加了自己的答案,而不是继续批评每个答案。
jaco0646
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.