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

我知道这里有很多关于这两种模式差异的post,但是有一些我找不到的东西。

从我一直在阅读的文章中,我发现工厂方法模式允许你定义如何创build一个具体的产品,但隐藏客户端的实现,因为他们会看到一个通用的产品。 我的第一个问题是关于抽象工厂。 它的作用是允许你创build具体对象的家族(这取决于你使用的具体工厂)而不是仅仅一个具体的对象? 抽象工厂是否只返回一个非常大的对象或许多对象,取决于你调用的方法?

我最后的两个问题是关于我在许多地方看到的一句话,我不能完全理解:

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

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

现在关于这个引用,Abstract Factory模式究竟是如何将对象实例化的责任委托给另一个对象的? 这是什么意思? 看起来抽象工厂模式也使用inheritance来完成build造过程,但我仍然在学习这些模式。

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

两者的区别

“工厂方法”和“抽象工厂”的主要区别在于工厂方法是单一方法,抽象工厂是对象。 我认为很多人把这两个术语弄糊涂了,开始互换使用。 我记得当我学到这些东西时,我很难find差别。

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

… Factory Method模式使用inheritance,并依赖于一个子类来处理所需的对象实例化。

报价假设一个对象在这里调用自己的工厂方法。 因此唯一可以改变返回值的是一个子类。

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

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

他们所说的是有一个对象A,他想创build一个Foo对象。 而不是使Foo对象本身(例如,使用工厂方法),它将获得不同的对象(抽象工厂)来创buildFoo对象。

代码示例

为了向你展示这个区别,下面是一个使用的工厂方法:

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 

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

在这里输入图像描述

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

在这里输入图像描述

抽象工厂

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

 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接口的目的。

因此我们引入工厂方法,以便将响应类的创build也抽象出来。

概要

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

在使用工厂方法时要小心,因为在创build对象时很容易破坏LSP( Liskovs替代原理 )。

AbstractFactory与工厂devise模式的区别如下:

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

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

AbstractFactory模式实现:

抽象工厂UML

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

抽象工厂UML

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

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

一般来说,你要做的是,创build产品,即宽带,电话线和移动是通过你的工厂方法 ,你知道什么属性,你有这些产品,它的直线前进。

现在,该公司希望为他们的客户提供他们的产品捆绑,即宽带,电话线和移动设备,在这里抽象工厂来玩。

换句话说, 抽象工厂就是其他工厂的组成人员,他们负责创build自己的产品, 抽象工厂知道如何将这些产品放在更有意义的方面。

在这种情况下, BundleFactory是Abstract Factory, BroadbandFactoryMobileFactoryMobileFactoryFactory 。 更简单地说,这些工厂将有工厂方法初始化单个产品。

下面的代码示例:

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

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

  1. 我的第一个问题是关于抽象工厂。 它的作用是允许你创build具体对象的家族(这取决于你使用的具体工厂)而不是仅仅一个具体的对象?

是。 Abstract Factory的意图是:

提供一个接口来创build相关或依赖对象的族,而不指定它们的具体类。


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

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

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

是。 工厂方法使用inheritance。

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

AbstractFactory定义了FactoryMethod,ConcreteFactory负责构buildConcreteProduct。 只需按照 本文中 的代码示例

你可以在相关的SEpost中find更多的细节:

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

devise模式:工厂vs工厂方法与抽象工厂

理解动机的差异:

假设你正在构build一个工具,你已经有了对象,并且具体实现了这些对象的相互关系。 既然你预见了对象的变化,你已经创build了一个间接方向,把创build对象变体的责任分配给另一个对象( 我们称之为抽象工厂 )。 由于您预见将来需要这些对象的变体的扩展,所以这种抽象发现很有好处。

这一思路中另一个相当有趣的动机就是这样一种情况,即整个组中的每一个或所有对象都将具有相应的变体。 基于某些条件,将使用任一种变体,并且在每种情况下,所有对象都必须具有相同的变体。 这可能有点反常理解,因为我们经常认为 – 只要对象的变体遵循共同的统一契约( 广义上的接口 ),具体的实现代码就不应该中断。 这里有趣的事实是,并不总是如此,特别是当预期的行为不能被编程合同模拟时。

一个简单的( 从GoF借鉴的想法 )是任何GUI应用程序都会说虚拟监视器,模拟MS或Mac或Fedora操作系统的外观。 在这里,例如,当窗口,button等所有窗口小部件对象具有除了从MAC变体派生的滚动条之外的MS变体时,该工具的目的会失败。

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

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

几个注释:

  • 如果您熟悉“模板方法”,那么您会发现在任何forms框架的程序的情况下,工厂方法通常会从模板方法中调用。 相比之下,应用程序的模板方法通常是特定algorithm的简单实现,而工厂方法则是无效的。
  • 此外,为了思想的完整性,使用上述框架,当工具制造者正在构build工具时,在每个工厂方法内部,而不是创build具体对象,他/她可以进一步将责任委托给一个抽象如果工具生成器预见了将来扩展的具体对象的变体,

示例代码:

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

使用最简单的界面使其变得非常简单,请关注“// 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机制必须使用inheritance(System.Object-> byte,float …); 所以如果你在程序中有inheritance,那么Factory(抽象工厂最不可能存在的)已经被devise了2. Creator(MyFactory)知道具体types,所以返回具体types对象给调用者(Main); 在抽象工厂返回types将是一个接口。

 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.要求:本田将创造“正规”,“体育”,但英雄会创造“黑马”,“体育”和“Scooty”。 2.为什么两个接口? 一个用于制造商types(IVehicleFactory)和另一个用于产品工厂(IVehicle); 其他的方式来理解2接口是抽象工厂是关于创build相关的对象2.捕获是IVehicleFactory的孩子返回和IVehicle(而不是在工厂具体); 所以我得到父variables(IVehicle); 然后通过调用CreateSingleVehicle然后将父对象转换为实际的子对象来创build实际的具体types。 会发生什么,如果我做RegularBike heroRegularBike = (RegularBike)hero.CreateSingleVehicle("Regular"); ; 你将得到ApplicationException,这就是为什么我们需要通用的抽象工厂,我会解释如果需要。 希望它能帮助初学者和中级听众。

任何时候我都会赞成Abstract Factory over Factory Method。 从上面的Tom Dalling的例子(伟大的解释btw)中,我们可以看到Abstract Factory更加可组合,因为我们需要做的就是将不同的Factory传递给构造函数(这里使用的构造函数dependency injection)。 但工厂方法要求我们引入一个新的类(更多的东西来pipe理)和使用子类。 总是比inheritance更喜欢构图。