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

注意:问题在post末尾。

我已经阅读了关于抽象工厂VS工厂方法的其他stackoverflow线程。 我了解每种模式的意图。 但是,我不清楚这个定义。

Factory Method定义了一个用于创build对象的接口,但是可以让子类决定实例化哪个接口。 工厂方法让类将实例化推迟到子类。

相比之下,抽象工厂提供了一个接口,用于创build相关或依赖对象的族,而不指定具体的类。

– John Feminella

抽象工厂看起来与工厂方法非常相似。 我画了几个UML类来说明我的观点。

注意:

  • 该图来自www.yuml.com,因此它们并不完美。 但是它的免费服务:)。
  • 图表可能不完美。 我仍然在学习GoF的devise模式。

工厂方法:

工厂方法

抽象工厂(只有1个成员):

抽象工厂(只有1个成员)

抽象工厂(更多会员):

替代文字

问题:

  1. 如果抽象工厂只有一个创build者和一个产品,它仍然是抽象工厂模式吗? (创build家庭的界面)
  2. 工厂方法的具体创build者可以从一个接口创build吗?还是必须来自一个类? (类将实例化推迟到子类)
  3. 如果抽象工厂只能有一个创build者和一个产品,那么抽象工厂工厂方法之间的唯一区别是,前者的创build者是一个接口,而后者的创build者是一个类?

希望这可以帮助。 它描述了各种types的工厂。 我使用Head First Design Patterns作为参考。 我用yuml.me来表示。

静态工厂

是一个具有静态方法的类来生成各种子types的产品。

静态工厂

简单的工厂

是一类可以产生各种子types的产品。 (比静态工厂好,当添加新types时,基本产品类不需要只改变简单工厂类)

简单的工厂

工厂方法

包含一种生成与其types相关的一种产品的方法。 (比简单工厂更好,因为types被推迟到一个子类。)

工厂方法

抽象工厂

生成一系列相关的types。 它比工厂方法明显不同,因为它有多种types的方法。 (这很复杂,请参考下图以获得更好的实际示例)。

抽象工厂

来自.NET Framework的示例

DbFactoriesProvider是一个简单的工厂,因为它没有子types。 DbFactoryProvider是一个抽象工厂,因为它可以创build各种相关的数据库对象,如连接和命令对象。

.NET Framework的抽象工厂

这两种模式当然是相关的!

模式之间的差异通常是有意的。

Factory Method意图是“定义一个创build对象的接口,但让子类决定实例化哪个类。Factory Method让类将实例化延迟到子类。

抽象工厂目的是“提供一个创build相关或依赖对象族的界面,而不必指定具体的类”。

纯粹基于这些意向性陈述(引自GoF),我认为Factory Method在某种意义上来说是一个“退化”的抽象工厂

他们通常倾向于实现不同,因为工厂方法抽象工厂简单得多。

然而,它们在实施中也是相关的。 正如GoF书所述,

AbstractFactory只声明创build产品的接口。 由ConcreteProduct子类来实际创build它们。 最常见的做法是为每个产品定义一个工厂方法。

这个c2维基对这个主题也有一些有趣的讨论。

看来,OP的(优秀)问题清单已被忽略。 目前的答案只是提供重新定义。 所以我会试图简洁地回答原来的问题。

  1. 如果抽象工厂只有一个创build者和一个产品,它仍然是抽象工厂模式吗? (创build家庭的界面)

没有 。 一个抽象工厂必须创build多个产品来构build“相关产品系列”。 规范的GoF示例创buildScrollBar()Window() 。 优点(和目的)是抽象工厂可以在其多个产品上实施一个共同的主题。

  1. 工厂方法的具体创build者可以从一个接口创build吗?还是必须来自一个类? (类将实例化推迟到子类)

首先,我们必须指出,当GoF写他们的书时,Java和C#都不存在。 GoF使用术语接口与特定语言引入的接口types无关。 因此,具体创build者可以从任何API创build。 模式中重要的一点是,API使用自己的Factory Method,所以只有一个方法的接口不能是一个Factory Method,也不能是一个Abstract Factory。

  1. 如果抽象工厂只能有一个创build者和一个产品,那么抽象工厂工厂方法之间的唯一区别是,前者的创build者是一个接口,而后者的创build者是一个类?

这个问题在上面的答案之后不再有效。 但是,如果您认为抽象工厂和工厂方法之间的唯一区别是创build的产品数量,请考虑客户端如何使用这些模式中的每一个。 抽象工厂通常被注入到客户端,并通过组合/委托来调用。 工厂方法必须被inheritance。 所以这一切都回到了旧的构成与inheritance的辩论。

但是这些答案提出了第四个问题!

  1. 因为只有一个方法的接口不能是一个Factory方法 ,而只能是一个Abstract Factory ,所以我们只用一个方法称之为一个创build接口?

如果方法是静态的,通常称为静态工厂 。 如果方法是非静态的,通常称为简单工厂 。 这些都不是GoF模式,但实际上它们更常用!

在我看来,两种模式之间的细微差别在于适用性 ,因此,正如已经说过的那样,在意图中

让我们回顾一下定义(来自维基百科)。

抽象工厂

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

工厂方法

定义用于创build对象接口 ,但让实现该接口的类决定实例化哪个类 。 Factory方法让类将实例化推迟到子类。

两种模式都允许将用户对象与创build所需实例(运行时解耦)分离,这是常见的方面。 这两种模式都可以根据任何特定的需求创build工厂的层次结构,这是另一个常见的方面。

抽象工厂允许在一个子类中创build几种不同types的实例,并在不同的子类中详细描述创build行为; 通常情况下,Factory方法声明只能根据子分类机制创build一个可以进行细化的对象types。 这是不同的。

通过总结。 假设Product定义了创build对象的超类,而ProductA和ProductB是两个不同的子类。 因此,抽象工厂方法将有两个方法createProductA()和createProductB(),它们将在其特定的子类中进行详细说明(就创build步骤而言):工厂子类详细说明两个定义的类的创build步骤创造中的对象。

根据上面的例子,工厂方法将以不同的方式实现,在许多工厂(每个工厂一个方法)中抽象创buildProductA和ProductB, 创build步骤的进一步专业化将在构build时被委托给层次结构。

如果我创build了一个抽象的(通过接口或抽象基类引用的) Factory Class来创build只有一个方法来创build对象的对象,那么它将是一个Factory Method

如果抽象工厂有超过1个方法来创build对象,那么它将是一个抽象工厂

比方说,我做了一个pipe理器,将处理MVC控制器的操作方法的需求。 如果它有一个方法,比方说创build将被用来创build视图模型的引擎对象,那么它将是一个工厂方法模式。 另一方面,如果它有两个方法:一个创build视图模型引擎,另一个创build动作模型引擎(或者任何你想调用的动作方法包含消费者的模型),那么它将是一个抽象工厂。

 public ActionResult DoSomething(SpecificActionModel model) { var actionModelEngine = manager.GetActionModelEngine<SpecificActionModel>(); actionModelEngine.Execute(SpecificActionModelEnum.Value); var viewModelEngine = manager.GetViewModelEngine<SpecificViewModel>(); return View(viewModelEngine.GetViewModel(SpecificViewModelEnum.Value); } 

虽然,自从StackOverflow的人在其他post(最年长到2009年)中对这个问题也提出质疑之后,我仍然找不到我想要的答案。

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

所以我通过networking做了几个小时的研究,回顾了一下这个例子,得出了这个结论,抽象工厂与工厂方法的主要区别是

  • 意图:一致性或“外观” :抽象工厂的目的是将具有相同样式的对象(例如相同的外观UI小部件,相同样式的汽车部件,来自同一操作系统的对象,等等)抽象工厂的许多例子都提到关键词“相同的外观和感觉”。
  • 形成更大组对象的对象 :抽象工厂创build一个对象族,形成一个更大的组对象,而不是一个对象。
  • 稍后添加一个新的样式 :如果我们继续使用Factory Method,并尝试添加一组新的样式到现有的基础架构,这将是痛苦的。 有了抽象工厂,我们只需要创build一个实现抽象工厂类的新的具体工厂。

反例是

  • 轿车中使用的跑车的一部分。 这种不一致可能会导致事故。
  • 不同的操作系统GUI小部件中的Windows风格的button。 这不会破坏任何东西,但会伤害像我这样的一些人的用户体验。
  • 后来我们发现我们的软件需要在下一次操作系统升级时运行,这需要不同的兼容系统对象,同时保持软件向后兼容。

因此,当一个最终的对象组应该具有相同的风格而没有一个对象的exception ,并且你想隐藏这个“保持相同样式”的细节时,我们应该使用抽象工厂。

据我了解抽象工厂和Factory方法定义的含义,第一个是在静态上下文中实现的,并根据input参数提供对象。

第二个使用已经创build的实现工厂方法接口的对象(家庭)。 工厂方法然后创build与原始对象相关的特定实例,而不pipe它是哪一个实例。

所以这通常会导致使用这两种模式在第一步你创build一个通用的对象,描述相关对象的家庭。 它由静态方法getInstance(“我的家族名称”)方法调用。 这种getInstance方法的实现决定了哪个家族对象将被创build。

然后我在新创build的family对象上调用createProduct()方法,并根据family对象返回新的产品。

似乎这些模式合作到每一个。

换句话说,抽象工厂主要关注“将会创build什么”以及工厂方法“如何”创build。

所有你必须记住的是抽象工厂是一个可以返回多个工厂的工厂 。 所以如果你有一个AnimalSpeciesFactory它可以返回这样的工厂:

Mamalfactory,BirdFactory,Fishfactory,ReptileFactory。 现在你有了一个来自AnimalSpeciesFactory的工厂,他们使用工厂模式来创build特定的目标文件。 例如,假设你从这个AnimalFactory获得了一个ReptileFactory,那么你可以提供创build爬行类的对象,例如:蛇,龟,蜥蜴对象。

工厂方法模式是创builddevise模式,它处理创build对象而不显示正在创build的对象的确切类别。 这种devise模式基本上允许类将实例推迟到子类。

抽象工厂模式为一组单个工厂提供封装,而不暴露具体的类。 在这个模型中,抽象工厂类的通用接口用于创build所需的具体对象,将对象的实现细节与其用法和构成分开。 这种devise模式在需要创build类似GUI组件的GUI应用程序中被广泛使用。

在谷歌上search时,我发现下面的博客里面都精彩地解释了devise模式。 看看这些

http://simpletechtalks.com/factory-design-pattern/

http://simpletechtalks.com/abstract-factory-design-pattern/