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


141

注意:问题在帖子末尾。

我已经阅读了有关Abstract Factory vs Factory Method的其他stackoverflow线程。我了解每种模式的意图。但是,我对该定义不清楚。

Factory Method定义了一个用于创建对象的接口,但是让子类决定要实例化的对象。工厂方法使类将实例化延迟到子类。

相比之下,抽象工厂提供了一个接口,用于创建相关或相关对象的族,而无需指定其具体类。

- 约翰·费米内拉

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

注意:

  • 该图来自www.yuml.com,因此它们的方向不完全正确。但它是免费的服务:)。
  • 这些图可能并不完美。我仍在学习GoF设计模式。

工厂方法:

工厂方法

抽象工厂(仅1个成员):

抽象工厂(仅1个成员)

抽象工厂(更多成员):

替代文字

问题:

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

1
注:当我提到接口时,我在考虑Java接口(带有抽象虚拟方法的抽象类)方面的思考。随意阐明抽象工厂和工厂方法在不同语言之间是否存在差异。

这里的基本区别是:stackoverflow.com/questions/1001767,虽然没有您要的具体..
nawfal 2013年

Answers:


134

希望这可以帮助。它描述了各种类型的工厂。我使用Head First设计模式作为参考。我用yuml.me作图

静态工厂

是带有“静态方法”的类,用于生产Product的各种子类型。

静态工厂

简单工厂

是可以产生各种子类型的产品的类。(它比静态工厂要好。添加新类型时,基本产品类不需要更改,仅简单工厂类即可)

简单工厂

工厂方法

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

工厂方法

抽象工厂

产生相关的类型族。它与工厂方法明显不同,因为它具有不止一种类型的方法。(这很复杂,请参见下图以获得更好的真实示例)。

抽象工厂

.NET Framework中的示例

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

.NET Framework中的抽象工厂


静态工厂和简单工厂之间的区别纯粹是CreateProduct方法位于不同的类中吗?
彼得·奥卡拉汉

4
如果在Factory Method的情况下,只是Product(作为一个抽象)然后是Product1and Product2,则不是更清楚吗?这将有助于说明Factory Method只是创建一个产品,而Abstract Factory或多或少是一系列Family方法聚集在一起的。
lllllll

79

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

模式之间的差异通常是出于意图。

意向工厂方法是“定义一个接口用于创建对象,让子类决定哪一个类实例化。工厂方法使一个类的实例化延迟到子类。”

意图抽象工厂是“用于创建相关或依赖的对象,而无需指定它们具体的类提供一个接口。”

纯粹基于这些intent语句(从GoF引用),我想说在某种意义上,工厂方法确实是一个“退化的” 抽象工厂,具有一个族。

它们的实现通常会有所不同,因为Factory方法Abstract Factory要简单得多。

但是,它们在实现中也相关。如GoF书中所述,

AbstractFactory仅声明用于创建产品的接口。实际创建它们的方法取决于ConcreteProduct子类。最常见的方法是为每种产品定义一种工厂方法。

这个c2 Wiki也对此主题进行了一些有趣的讨论。


7
我既不了解评论,也不理解投票。你能详细说明吗?
Don Roby 2012年

好吧,在我看来答案似乎很夸张……没有真正的例子……过于广泛……
Novalis 2012年

14

看来,OP的(优秀)问题列表已被忽略。当前答案仅提供重新定义。因此,我将尝试简洁地解决原始问题。

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

没有。抽象工厂必须创建多个产品才能制作“相关产品系列”。规范的GoF示例创建ScrollBar()Window()。优点(和目的)是,抽象工厂可以在其多个产品中强制使用一个公共主题。

  1. 可以从接口创建Factory Method具体创建器,还是必须从类创建它?(类将实例化延迟到子类)

首先,我们必须注意,GoF编写本书时既没有Java也没有C#。术语接口的GoF使用与特定语言引入的接口类型无关。因此,可以从任何API创建具体的创建者。模式中的重点是API使用了自己的Factory方法,因此只有一个方法的接口不能是Factory方法,而只能是Abstract Factory。

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

按照上述答案,该问题不再有效;但是,如果您认为抽象工厂和工厂方法之间的唯一区别是创建的产品数量,请考虑客户端如何使用这些模式中的每一个。通常将抽象工厂注入其客户端,并通过组合/委托进行调用。工厂方法必须被继承。因此,这一切都可以追溯到旧的合成与继承之争。

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

  1. 由于只有一个方法的接口不能是工厂方法,而只能是抽象工厂,所以我们怎么称呼只有一个方法的创建接口?

如果该方法是静态的,则通常称为“ 静态工厂”。如果该方法是非静态的,则通常称为简单工厂。这些都不是GoF模式,但在实践中它们更常用!


1
关于合成与继承,我一直想知道:是否也可以使用Factory Method模式进行合成?什么会阻止人们组成或向客户注入合适的混凝土工厂?还是这已经超出了模式范围?
georaldc

1
@georaldc,来自GoF(第107页)“ 工厂方法使类将实例化延迟到子类。 ”换句话说,工厂方法根据定义使用继承。
jaco0646

4

我认为,这两种模式之间的细微差别在于适用性,因此,正如已经说过的,在Intent中

让我们回顾一下定义(均来自Wikipedia)。

抽象工厂

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

工厂方法

定义用于创建对象接口,但是让实现该接口的类决定要实例化的类。Factory方法允许类将实例化延迟到子类。

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

Abstract Factory允许在一个子类中创建几种不同类型的实例,并在其不同的子类中具体说明创建行为;通常,Factory方法声明仅创建一种类型的对象,该对象可以根据子分类机制进行特定化。就是这样。

通过总结。假设Product定义了创建对象的超类,而ProductA和ProductB是两个不同的子类。因此,Abstract Factory方法将具有两个方法createProductA()和createProductB(),这两个方法将在其特定的子类中进行具体化(根据创建步骤):factory子类具体化了两个已定义类的创建步骤正在创建的对象。

根据上面的示例,工厂方法将以不同的方式实现,将在多个工厂中对ProductA和ProductB的创建进行抽象(每个工厂一个方法),并且创建步骤的进一步专业化将在构建时委派给层次结构。


2

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

如果抽象工厂具有多种创建对象的方法,则它将是抽象工厂

假设我制作了一个Manager,它将处理MVC控制器的操作方法的需求。如果有一种方法,比如说创建将用于创建视图模型的引擎对象,那么它将是一种工厂方法模式。另一方面,如果它有两种方法:一种用于创建视图模型引擎,另一种用于创建动作模型引擎(或者您想要调用的动作方法包含使用者的模型),那么它将是一个抽象工厂。

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

1

尽管距StackOverflow的人们在其他帖子中对此问题提出类似质疑已经有很多年了(最早到2009年),但我仍然找不到我想要的答案。


因此,我花了几个小时通过网络进行研究,回顾了示例,得出了这个结论,“抽象工厂”与“工厂方法”的主要区别在于

  • 目的:连贯性或“外观”:Abstract Factory的目的是将具有相同样式的一组对象(例如,相同的外观UI小部件,相同样式的汽车部件,来自相同OS的对象,等),来自Abstract Factory的许多示例都提到了关键字“相同的外观”。
  • 组成更大的组对象的对象:抽象工厂创建了一个组成更大的组对象的对象族,而不是单个对象。
  • 以后添加新样式:如果我们继续使用Factory Method并尝试向现有基础结构中添加新样式集,那将很痛苦。使用Abstract Factory,我们所要做的只是简单地创建一个实现了abstract factory类的新的具体工厂。

相反的例子是

  • 轿车中用于跑车的汽车零件。这种不一致可能导致事故。
  • 不同OS GUI小部件中的Windows样式的按钮。它不会破坏任何东西,但会损害像我这样的某些人的用户体验。
  • 后来,我们发现我们的软件需要在下一个OS升级中运行,该升级需要不同的兼容系统对象集,同时还要使软件向后兼容。

因此,当最终对象组应具有相同的样式而没有对象例外,而您要隐藏此“保持相同的样式”详细信息时,则应使用Abstract Factory。


0

据我了解的含义o抽象工厂和工厂方法定义,第一个在静态上下文中实现,并基于输入参数提供对象。

第二个使用实现工厂方法接口的已创建对象(家族)。然后,factory方法将创建与原始对象相关的特定实例,无论它是哪一个。

因此,这通常导致同时使用这两种模式,在第一步中,您将创建一些描述相关对象族的常规对象。它由静态方法getInstance(“ my family name”)方法调用。这种getInstance方法的实现决定了将创建哪个系列对象。

然后,我在新创建的系列对象上调用createProduct()方法,并将根据该系列对象返回新产品。

这些模式似乎相互配合。

换句话说,Abstract Factory将专注于“ WHAT”,并将创建Factory方法“ HOW”。


0

您只需要记住,抽象工厂就是可以返回多个工厂的工厂。因此,如果您有AnimalSpeciesFactory,它可以像这样返回工厂:

恶意工厂,BirdFactory,Fishfactory,ReptileFactory。现在您有了AnimalSpeciesFactory的一个工厂,它们将使用工厂模式来创建特定的objexts。例如,假设您从此AnimalFactory中获得了ReptileFactory,那么您可以提议创建爬行动物对象,例如:蛇,龟,蜥蜴对象。


0
/*
//Factory methods:

//1. Factory Method - Abstract Creator Class



#include <iostream>
#include <string.h>
using namespace std;

const std::string nineNintyCC = std::string("990CC");
const std::string thousandTwoHundredCC = std::string("1200CC");
const std::string ThousandFiveHundredCC = std::string("1500CC");
const std::string fiveThousandCC = std::string("5000CC");

// Product
class Engine
{
    public:
    virtual void packEngine() = 0;  
};

// Concrete products
// concrete product class one
class C990CCEngine: public Engine
{

    public:
    void packEngine()
    {
       cout << "Pack 990CC engine" << endl;   
    }
};

// concrete class Two
class C1200CCEngine: public Engine
{   public:
    void packEngine()
    {
        cout << "pack 1200CC engine" << endl;
    }

};

// Concrete class Three
class C1500CCEngine: public Engine
{
    public:
    void packEngine()
    {
        cout << "Pack 1500CC engine" << endl;
    }

};


// Car Factory:
class CarFactory{
    public:

    virtual Engine* createEngine(const std::string& type) = 0;
};
class Factory: public CarFactory
{
    public:
     Engine *createEngine(const std::string& type)
     {

          if(0 == nineNintyCC.compare(type))
          {    
             return new C990CCEngine;
          }
          else if(0 == thousandTwoHundredCC.compare(type))
          {
             return new C1200CCEngine;
          }
          else if(0 == ThousandFiveHundredCC.compare(type))
          {
             return new C1500CCEngine;
          } 
          else
           {
                 cout << "Invalid factory input" << endl;
             return NULL;
           }
           return NULL;
     }
};

int main()
{

    CarFactory* ptr = new Factory;
    Engine*pEngine =  ptr->createEngine(nineNintyCC);
    if(pEngine)
    {
        pEngine->packEngine();
        delete pEngine;
    }
    else
    {
        cout << "No engine exists of your type in our factory" << endl;
    }
    pEngine =  ptr->createEngine(ThousandFiveHundredCC);
    if(pEngine)
    {
        pEngine->packEngine();
        delete pEngine;
    }
    else
    {
        cout << "No engine exists of your type in our factory" << endl;
    }
    pEngine =  ptr->createEngine(thousandTwoHundredCC);
    if(pEngine)
    {
        pEngine->packEngine();
        delete pEngine;
    }
    else
    {
        cout << "No engine exists of your type in our factory" << endl;
    }
    pEngine = ptr-> createEngine(fiveThousandCC);
    if(pEngine)
    {
        pEngine->packEngine();
        delete pEngine;
    }
    else
    {
        cout << "No engine exists of your type in our factory" << endl;
    }
    return 0;
}

*/
/*
//
// interface product
#include <iostream>
#include <string>
using namespace std;

class Engine
{
 public:
 virtual void EngineType() = 0;

};

// concrte product
class AltoEngine: public Engine
{
  public:
  void EngineType()
  {
      cout << "Alto Engine" << endl;
  }
};

//Concrte product
class SwiftEngine : public Engine
{
    public:
    void EngineType()
    {
        cout << "Swift Engine" << endl;    
    }
};

class Body
{
   public:
    virtual void bodyType() = 0;

};

class AltoBody: public Body
{
  public:  
    virtual void bodyType()
    {
        cout << "Alto Car Body" << endl;
    }
};

class SwiftBody : public Body
{
    public:
    void bodyType()
    {
        cout << "SwiftCar Body" << endl;
    }

};


class CarFactory
{
   public:
   virtual Engine* createEngineProduct() = 0;
   virtual Body*   createBodyPoduct() = 0;
};
class AltoCarFactory: public CarFactory
{
    public:
    Engine * createEngineProduct()
    {
        return new AltoEngine;
    }
    Body* createBodyPoduct()
    {
        return new AltoBody;
    }

};

class SwiftCarFactory: public CarFactory
{
    public:
    Engine * createEngineProduct()
    {
        return new SwiftEngine;
    }
    Body* createBodyPoduct()
    {
        return new SwiftBody;
    }

};

int main()
{

    CarFactory* pAltoFactory = new AltoCarFactory;
    Engine* pAltoEngine = pAltoFactory->createEngineProduct();
    pAltoEngine->EngineType();
    Body* pAltoBody = pAltoFactory->createBodyPoduct();
    pAltoBody->bodyType();



    CarFactory* pSwiftFactory = NULL;
    pSwiftFactory = new SwiftCarFactory;
    Engine* pSwiftEngine = pSwiftFactory->createEngineProduct();
    pSwiftEngine->EngineType();
    Body* pSwfitBody = pSwiftFactory->createBodyPoduct();
    pSwfitBody->bodyType();
    delete pAltoBody;
    delete pAltoFactory;
    delete pSwfitBody;
    delete pSwiftFactory;
    return 0;
}
*/

/*

// One more Factory example;

#include <iostream>
#include <string>
using namespace std;

const std::string maruthi = std::string("Maruthi");
const std::string fiat = std::string("Fiat");
const std::string renault = std::string("Renault");
// Interface
class CarEngine
{
 public:
    virtual void engineType() = 0;
};

// Concrete class
class FiatEngine: public CarEngine
{
  public:
  void engineType()
  {
      cout << "Fait Engine Engine" << endl;
  }

};
// ConcreteClass
class RenaultEngine : public CarEngine
{
    public:
    void engineType()
    {
        cout << "Renault Engine" << endl;
    }

};
// Concrete class
class MaruthiEngine : public CarEngine
{
    public:
    void engineType()
    {
        cout << "Maruthi Engine" << endl;
    }
};


// Factory
class CarFactory
{
    public:
    virtual CarEngine* createFactory(const std::string&) = 0;
};

// EngineFactory
class CarEngineFactory : public CarFactory
{
     public:
     CarEngine* createFactory(const std::string&  type)
     {
          if(0 == maruthi.compare(type))
          {
              return new MaruthiEngine;

          }
          else if(0 == fiat.compare(type))
          {
              return  new FiatEngine;
          }
          else if(0 == renault.compare(type))
          {
              return new RenaultEngine;
          }
          else
          {
              cout << "Invalid Engine type" << endl;
              return NULL;
          }
     }

  };

int main()
{
    CarFactory* pCarFactory = new CarEngineFactory;
    CarEngine* pMaruthiCarEngine = pCarFactory->createFactory(maruthi);
    pMaruthiCarEngine->engineType();

    CarEngine* pFiatCarEngine = pCarFactory->createFactory(fiat);
    pFiatCarEngine->engineType();


    CarEngine* pRenaultCarEngine = pCarFactory->createFactory(renault);
    pRenaultCarEngine->engineType();

    return 0;
}


*/


/*

// One more Factory example;

#include <iostream>
#include <string>
using namespace std;

const std::string maruthi = std::string("Maruthi");
const std::string fiat = std::string("Fiat");
const std::string renault = std::string("Renault");


// Interface
class CarEngine
{
 public:
    virtual void engineType() = 0;
};

// Concrete class
class FiatEngine: public CarEngine
{
  public:
  void engineType()
  {
      cout << "Fait Car Engine" << endl;
  }

};

// ConcreteClass
class RenaultEngine : public CarEngine
{
    public:
    void engineType()
    {
        cout << "Renault Car Engine" << endl;
    }

};

// Concrete class
class MaruthiEngine : public CarEngine
{
    public:
    void engineType()
    {
        cout << "Maruthi Car Engine" << endl;
    }
};

// Interface
class CarBody
{
 public:
    virtual void bodyType() = 0;
};

// Concrete class
class FiatBody: public CarBody
{
  public:
  void bodyType()
  {
      cout << "Fait car Body" << endl;
  }

};

// ConcreteClass
class RenaultBody : public CarBody
{
    public:
    void bodyType()
    {
        cout << "Renault Body" << endl;
    }

};

// Concrete class
class MaruthiBody : public CarBody
{
    public:
    void bodyType()
    {
        cout << "Maruthi body" << endl;
    }
};


// Factory
class CarFactory
{
    public:
    virtual CarEngine* createCarEngineProduct() = 0;
    virtual CarBody* createCarBodyProduct() = 0;
};

// FiatFactory
class FaitCarFactory : public CarFactory
{
     public:
     CarEngine* createCarEngineProduct()
     {
        return new FiatEngine; 
     }
     CarBody* createCarBodyProduct()
     {
         return new FiatBody;
     }
};

// Maruthi Factory
class MaruthiCarFactory : public CarFactory
{
     public:
     CarEngine* createCarEngineProduct()
     {
         return new MaruthiEngine;
     }
     CarBody* createCarBodyProduct()
     {
         return new MaruthiBody;
     }

};

// Renault Factory
class RenaultCarFactory : public CarFactory
{
     public:
    CarEngine* createCarEngineProduct()
    {
        return new RenaultEngine;
    }

    CarBody* createCarBodyProduct()
    {
        return new RenaultBody;
    }

};


int main()
{

   // Fiat Factory
   CarFactory* pFiatCarFactory = new FaitCarFactory;
   CarEngine* pFiatEngine = pFiatCarFactory->createCarEngineProduct();
   CarBody*  pFiatBody = pFiatCarFactory->createCarBodyProduct();
   pFiatEngine->engineType();
   pFiatBody->bodyType();

   // Renault Car Factory
    return 0;
}

*/

-1

工厂方法模式是一种创建性设计模式,该模式处理创建对象而不显示正在创建的对象的确切类。这种设计模式基本上允许类将实例化推迟到子类。

抽象工厂模式将封装封装到一组单独的工厂中,而不会暴露具体的类。在此模型中,抽象工厂类的通用接口用于创建所需的具体对象,从而将对象的实现细节与其用法和组成分开。此设计模式广泛用于需要创建类似GUI组件的GUI应用程序中。

在Google上搜索时,我出现了一个博客,该博客很好地解释了两种设计模式。看看这些

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

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

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.