我知道有很多关于这两种模式之间差异的帖子,但有一些我找不到的东西。
从我一直在阅读的内容中,我看到工厂方法模式允许您定义如何创建单个具体产品,但是从客户端隐藏实现,因为他们将看到通用产品。 我的第一个问题是抽象工厂。 它的作用是允许您创建具体对象系列(可能取决于您使用的特定工厂)而不仅仅是单个具体对象? 抽象工厂是否只返回一个非常大的对象或许多对象,具体取决于您调用的方法?
我的最后两个问题是关于我在很多地方看到过的单一引言,我无法完全理解:
两者之间的一个区别是,使用抽象工厂模式,类通过组合将对象实例化的责任委托给另一个对象,而工厂方法模式使用继承并依赖子类来处理所需的对象实例化。
我的理解是工厂方法模式有一个Creator接口,它将使ConcreteCreator负责知道要实例化的ConcreteProduct。 这是通过使用继承来处理对象实例化的意思吗?
现在关于那个引用,抽象工厂模式究竟是如何通过合成将对象实例化的责任委托给另一个对象? 这是什么意思? 看起来抽象工厂模式也使用继承来完成构建过程,但是我仍然在学习这些模式。
任何帮助,尤其是最后一个问题,将不胜感激。
#1楼
AbstractFactory和Factory设计模式之间的区别如下:
- Factory Method仅用于创建一个产品,但Abstract Factory用于创建相关或依赖产品的族。
- Factory Method模式向客户端公开一个方法来创建对象,而在Abstract Factory的情况下,它们公开了一系列相关对象,这些对象可能包含这些Factory方法。
- 工厂方法模式隐藏单个对象的构造,其中抽象工厂方法隐藏了一系列相关对象的构造。 抽象工厂通常使用(一组)工厂方法实现。
- AbstractFactory模式使用组合将创建对象的职责委托给另一个类,而Factory设计模式使用继承并依赖派生类或子类来创建对象。
- Factory Method模式背后的想法是它允许客户端不知道在运行时需要创建哪些具体类的情况,但是只想获得一个可以完成工作的类,而AbstractFactory模式是最好的当您的系统必须创建多个系列的产品或您想要提供产品库而不暴露实现细节时使用。
工厂方法模式实施:
AbstractFactory模式实现:
#2楼
Abstract Factory是一个用于创建相关产品的界面,但Factory Method只是一种方法。 抽象工厂可以通过多种工厂方法实现。
#3楼
让我们说清楚大多数时候在生产代码中,我们使用抽象工厂模式,因为类A用接口B编程.A需要创建B的实例。所以A必须有一个工厂对象来生成B的实例所以A不依赖于B的任何具体实例。希望它有所帮助。
#4楼
- 我的第一个问题是抽象工厂。 它的作用是允许您创建具体对象系列(可能取决于您使用的特定工厂)而不仅仅是单个具体对象?
是。 抽象工厂的目的是:
提供用于创建相关或从属对象族的接口,而无需指定其具体类。
- 抽象工厂是否只返回一个非常大的对象或许多对象,具体取决于您调用的方法?
理想情况下,它应该根据客户端调用的方法返回一个对象。
- 我的理解是工厂方法模式有一个Creator接口,它将使ConcreteCreator负责知道要实例化的ConcreteProduct。 这是通过使用继承来处理对象实例化的意思吗?
是。 工厂方法使用继承。
- 抽象工厂模式通过组合将对象实例化的责任委托给另一个对象? 这是什么意思?
AbstractFactory定义了FactoryMethod,ConcreteFactory负责构建ConcreteProduct。 只需按照 本文中 的代码示例进行操作即可 。
您可以在相关的SE帖子中找到更多详细信息:
#5楼
我随时都喜欢抽象工厂而不是工厂方法。 从上面的Tom Dalling的例子(很好的解释),我们可以看到抽象工厂更具可组合性,因为我们需要做的就是将不同的工厂传递给构造函数(这里使用的构造函数依赖注入)。 但是Factory Method要求我们引入一个新类(更多要管理的东西)并使用子类。 总是喜欢组合而不是继承。
#6楼
了解动机的差异:
假设您正在构建一个工具,您可以在其中创建对象,并具体实现对象的相互关系。 由于您预见到对象的变化,您通过将创建对象变体的责任分配给另一个对象( 我们称之为抽象工厂 )来创建间接。 这种抽象发现了很大的好处,因为您预见到未来的扩展需要这些对象的变体。
在这一系列思路中另一个相当有趣的动机是整个组中的每个或每个对象都将具有相应的变体。 基于某些条件,将使用任一变体,并且在每种情况下,所有对象必须具有相同的变体。 理解这可能有点反直觉,因为我们经常认为 - 只要对象的变体遵循一个统一的统一契约( 广义上的接口 ),具体的实现代码就永远不会破坏。 这里有趣的事实是,并非总是如此,尤其是当预期行为无法通过编程合同建模时。
一个简单的( 借用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
}
….
}
#7楼
考虑这个例子以便于理解。
电信公司提供什么? 例如,宽带,电话线和移动设备,您被要求创建一个应用程序,以便向其客户提供产品。
通常你在这里做的是,通过你的工厂方法创建产品,即宽带,电话线和移动设备,你知道你对这些产品有什么属性,而且非常简单。
现在,该公司希望为他们的客户提供他们的产品包括宽带,电话线和移动设备,这里有抽象工厂 。
换句话说, 抽象工厂是负责创建自己的产品的其他工厂的组成, 抽象工厂知道如何使这些产品在其自身职责方面更有意义。
在这种情况下, BundleFactory
是抽象工厂, BroadbandFactory
, PhonelineFactory
和MobileFactory
是Factory
。 为了简化更多,这些工厂将采用工厂方法来初始化各个产品。
请看下面的代码示例:
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.
}
}
希望这可以帮助。
#8楼
要使界面最小化非常简单,请关注“// 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(抽象工厂最不可能存在)已经存在于设计中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。要求:本田将创造“常规”,“体育”,但英雄将创造“DarkHorse”,“运动”和“Scooty”。 2.为什么两个接口? 一个用于制造商类型(IVehicleFactory),另一个用于产品工厂(IVehicle); 理解2个接口的其他方法是抽象工厂是关于创建相关对象的2.捕获是IVehicleFactory的子项返回和IVehicle(而不是工厂中的具体); 所以我得到父变量(IVehicle); 然后我通过调用CreateSingleVehicle创建实际的具体类型,然后将父对象转换为实际的子对象。 如果我做RegularBike heroRegularBike = (RegularBike)hero.CreateSingleVehicle("Regular");
会发生什么? ; 您将获得ApplicationException,这就是我们需要通用抽象工厂的原因,如果需要我会解释。 希望它有助于从初学者到中级受众。
#9楼
真实生活的例子。 (容易记住)
厂
想象一下,你正在建造一座房子,然后你会接近木匠的门。 你给出了门和你的要求的测量,他将为你建造一扇门。 在这种情况下,木匠是门的工厂。 您的规格是工厂的输入,门是工厂的输出或产品。
抽象工厂
现在,考虑门的相同例子。 你可以去木匠,或者你可以去塑料门店或PVC商店。 他们都是门工厂。 根据具体情况,您可以决定需要接近哪种工厂。 这就像一个抽象工厂。
我在这里解释了Factory方法模式和抽象工厂模式,从不使用它们解释问题然后通过使用上述模式解决问题https://github.com/vikramnagineni/Design-Patterns/tree/master
#10楼
请允许我准确地说出来。 大多数答案已经解释过,也提供了图表和示例。 所以我的anwer只是一个班轮。 我自己的话: - “抽象工厂模式在多个工厂方法实现上添加抽象层。 表示抽象工厂包含或复合一个或多个工厂方法模式“
#11楼
上面的很多答案都没有提供抽象工厂和工厂方法模式之间的代码比较。 以下是我尝试通过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();
}
}
#12楼
抽象工厂与工厂方法的主要区别在于抽象工厂由Composition实现 ; 但工厂方法由继承实现 。
是的,你读得正确:这两种模式之间的主要区别在于旧的构成与继承辩论。
UML图可以在(GoF)书中找到。 我想提供代码示例,因为我认为在这个线程中结合前两个答案中的示例将比单独的答案更好地演示。 另外,我在课程和方法名称中使用了本书中的术语。
抽象工厂
- 这里要抓住的最重要的一点是抽象工厂注入客户端。 这就是为什么我们说抽象工厂是由Composition实现的。 通常,依赖注入框架会执行该任务; 但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()
的子类。 这就是为什么我们说Factory Method是通过继承实现的。 - 第二个关键点是要记住,工厂方法模式只不过是模板方法模式的专业化。 这两种模式共享相同的结构。 它们的目的不同。 工厂方法是创造性的(它构建一些东西)而模板方法是行为的(它计算某些东西)。
- 最后,要注意的第三点是
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();
}
}
杂项。 &杂项工厂模式
请注意,尽管GoF定义了两种不同的Factory模式,但这些模式并不是唯一存在的Factory模式。 它们甚至不一定是最常用的工厂模式。 一个着名的第三个例子是Josh Bloch的Effective Java的静态工厂模式。 Head First Design Patterns一书包含了另一种他们称之为Simple Factory的模式。
不要陷入假设每个工厂模式必须与GoF匹配的模式。
#13楼
Factory方法依赖于继承:将对象创建委托给子类,子类实现工厂方法来创建对象。
Abstract Factory依赖于对象组合:对象创建在工厂界面中公开的方法中实现。
工厂和抽象工厂模式的高级图,
有关Factory方法的更多信息,请参阅此文章 。
有关抽象工厂方法的更多信息,请参阅此文章 。
#14楼
抽象工厂 :工厂工厂; 将个人但相关/依赖工厂分组在一起而不指定其具体类别的工厂。 抽象工厂实例
Factory :它提供了一种将实例化逻辑委托给子类的方法。 工厂模式示例
#15楼
两者的区别
“工厂方法”和“抽象工厂”之间的主要区别在于工厂方法是单个方法,抽象工厂是对象。 我想很多人会把这两个术语弄糊涂,并开始互换使用它们。 我记得当我学习它们时,我很难找到确切的差异。
因为工厂方法只是一个方法,所以它可以在子类中重写,因此引用的后半部分:
... 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();
}
}
这是一个使用的抽象工厂:
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
#16楼
抽象工厂使用抽象方法创建基类,这些方法定义应该创建的对象的方法。 派生基类的每个工厂类都可以创建自己的每个对象类型的实现。
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(/*....*/);
}
}
工厂方法
HTTP服务器中的问题是我们总是需要对每个请求进行响应。
public interface IHttpRequest
{
// .. all other methods ..
IHttpResponse CreateResponse(int httpStatusCode);
}
如果没有工厂方法,HTTP服务器用户(即程序员)将被迫使用特定于实现的类,这会IHttpRequest
接口的用途。
因此,我们引入工厂方法,以便抽象出响应类的创建。
摘要
不同之处在于包含工厂方法的类的预期目的 不是创建对象 ,而抽象工厂只应用于创建对象。
在使用工厂方法时应该注意,因为在创建对象时很容易破坏LSP( Liskov替换原则 )。