抽象工厂模式与工厂方法的区别

Sil*_*olt 420 design-patterns factory-method factory-pattern abstract-factory

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

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

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

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

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

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

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

Tom*_*ing 461

两者的区别

"工厂方法"和"抽象工厂"之间的主要区别在于工厂方法是单个方法,抽象工厂是对象.我想很多人会把这两个术语弄糊涂,并开始互换使用它们.我记得当我学习它们时,我很难找到确切的差异.

因为工厂方法只是一个方法,所以它可以在子类中重写,因此引用的后半部分:

... Factory Method模式使用继承并依赖子类来处理所需的对象实例化.

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

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

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

他们所说的是有一个对象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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的解释.但是,最重要的部分是什么,没有得到答复,那就是:何时使用一个,何时使用其他模式? (12认同)
  • 不确定这是否正确.很确定Factory Method是一种以**工厂方法命名的设计模式**,但涉及类结构和继承.这不是一种方法. (8认同)
  • 所以这样说是否正确:工厂方法可以是所有常规类中具有不同目的的方法。但是抽象工厂是客户端使用的类/对象,只负责创建家庭中的一些产品? (2认同)

jga*_*fin 117

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

在此输入图像描述

Factory方法只是用于在类中创建对象的简单方法.它通常添加在聚合根中(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(/*....*/);
      }
}
Run Code Online (Sandbox Code Playgroud)

工厂方法

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

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

    IHttpResponse CreateResponse(int httpStatusCode);
}
Run Code Online (Sandbox Code Playgroud)

如果没有工厂方法,HTTP服务器用户(即程序员)将被迫使用特定于实现的类,这会破坏IHttpRequest接口的用途.

因此,我们引入工厂方法,以便抽象出响应类的创建.

摘要

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

在使用工厂方法时应该注意,因为在创建对象时很容易破坏LSP(Liskov替换原则).

  • 因为没有人想投资创意. (53认同)
  • 抽象工厂应该创建的不仅仅是"Button()"来制作"相关产品系列".例如,规范的GoF示例创建`ScrollBar()`和`Window()`.优点是抽象工厂可以在其多个产品中实施共同主题. (4认同)
  • 为什么我们需要一个具体的产品? (3认同)
  • @AndrewS:回答你的问题。如果我们不需要为相同的抽象(接口)提供不同的具体产品(类),我们可能需要构建器模式而不是工厂模式。_(迟到总比不到好 ;))_ (2认同)

小智 91

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

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

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

AbstractFactory模式实现:

抽象工厂UML

  • 嗯,不确定抽象工厂示例.我认为形状工厂和颜色工厂应该实现相同的方法.但是,如果我是对的,那么样本没有任何意义. (11认同)
  • 要点是正确的; 然而,这两个图都是完全错误的并且非常误导.请参阅@Trying中的下图,了解Abstract Factory的精确模型. (3认同)

Try*_*ing 24

Abstract Factory是一个用于创建相关产品的界面,但Factory Method只是一种方法.抽象工厂可以通过多种工厂方法实现.

抽象工厂UML

  • 你已经发布了相同的答案[这里](http://stackoverflow.com/questions/1001767/what-is-the-basic-difference-between-factory-and-abstract-factory-patterns/20648551#20648551) .如果您认为此问题类似,请将其标记为重复. (9认同)
  • 图中的第二个标题应为“这两个_可能_工厂方法”。如果没有看到实现,我们不知道它们是否遵循工厂方法模式。一个常见的误解是,抽象工厂的方法自动成为工厂方法。这不是真的。有两种不同的 GoF 模式是有原因的:它们的实现方式不同。 (2认同)

jac*_*646 19

抽象工厂与工厂方法的主要区别在于抽象工厂由Composition实现 ; 但工厂方法由继承实现.

是的,你读得正确:这两种模式之间的主要区别在于旧的构成与继承辩论.

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

抽象工厂

  1. 这里要抓住的最重要的一点是抽象工厂注入客户端.这就是为什么我们说抽象工厂是由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();
    }
}
Run Code Online (Sandbox Code Playgroud)

工厂方法

  1. 这里要抓住的最重要的一点ConcreteCreator 客户.换句话说,客户端是其父类定义的子类factoryMethod().这就是为什么我们说Factory Method是通过继承实现的.
  2. 第二个关键点是要记住,工厂方法模式只不过是模板方法模式的专业化.这两种模式共享相同的结构.它们的目的不同.工厂方法是创造性的(它构建一些东西)而模板方法是行为的(它计算某些东西).
  3. 最后,要注意的第三点是Creator(父)类调用它自己的factoryMethod().如果我们anOperation()从父类中删除 ,只留下一个方法,则它不再是Factory Method模式.换句话说,在父类中使用少于两个方法不能实现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();
    }
}
Run Code Online (Sandbox Code Playgroud)

杂项.&杂项工厂模式

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

不要陷入假设每个工厂模式必须与GoF匹配的模式.

  • 基于良好示例的出色且非常明确的答案,是本主题 IMO 中最好的。 (3认同)
  • @YaroslavFedoruk,GoF 书允许“公共”工厂方法,并且该方法甚至不必是“抽象”;但关键点是该方法是用于继承的,因此它不能(例如)是“static”或“final”。我在这里将方法设置为“protected”和“abstract”,以突出显示(必需的)可扩展性。 (2认同)

Abd*_*nim 11

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

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

通常你在这里做的是,通过你的工厂方法创建产品,即宽带,电话线和移动设备,你知道你对这些产品有什么属性,而且非常简单.

现在,该公司希望为他们的客户提供他们的产品包括宽带,电话线和移动设备,这里有抽象工厂.

换句话说,抽象工厂是负责创建自己的产品的其他工厂的组成,抽象工厂知道如何使这些产品在其自身职责方面更有意义.

在这种情况下,BundleFactory是抽象工厂BroadbandFactory,PhonelineFactory并且MobileFactoryFactory.为了简化更多,这些工厂将采用工厂方法来初始化各个产品.

请看下面的代码示例:

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.
    }
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.


小智 9

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

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

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

图表

有关工厂方法的更多信息,请参阅这篇文章

有关抽象工厂方法的更多信息,请参阅这篇文章


Vik*_*eni 7

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

工厂

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

抽象工厂

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

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