【问题标题】:Design Patterns: Abstract Factory vs Factory Method设计模式:抽象工厂与工厂方法
【发布时间】:2011-05-11 17:19:02
【问题描述】:

注意:问题在文章末尾。

我已阅读有关 抽象工厂与工厂方法 的其他 * 线程。我了解每种模式的意图。但是,我并不清楚定义。

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

相比之下,抽象工厂 提供创建接口 相关或受抚养的家庭 没有指定它们的对象 具体类。

-John Feminella

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

注意:

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

工厂方法:

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

抽象工厂(更多成员):

问题:

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

【问题讨论】:

  • 注意:当我提到接口时,我更多地考虑的是 Java 接口(具有抽象虚拟方法的抽象类)。随意澄清不同语言的抽象工厂和工厂方法之间是否存在差异。
  • 这里有一个基本的区别:*.com/questions/1001767,虽然不像你问的那么具体..
  • 工厂方法定义了一个方法而不是一个接口。如果你定义一个方法来创建产品和子类化,那就是工厂方法。如果你定义了一个抽象类和子类,那就是抽象工厂。

标签: design-patterns language-agnostic uml factory-method abstract-factory


【解决方案1】:

希望这会有所帮助。它描述了各种类型的工厂。我使用了Head First Design Patterns 这本书作为参考。我用yuml.me 绘制图表。

静态工厂

是一个带有静态方法的类,用于生产各种子类型的产品。

简单工厂

是一个可以产生各种子类型Product的类。 (它比静态工厂好。当添加新类型时,基础产品类不需要更改,只需简单工厂类)

工厂方法

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

抽象工厂

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

.NET 框架的示例

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

​​​​

【讨论】:

  • 静态工厂和简单工厂的区别仅仅在于 CreateProduct 方法位于不同的类中吗?
  • 如果在工厂方法的情况下,只有Product(作为摘要),然后Product1Product2作为儿子,这不是更清楚吗?这将有助于说明工厂方法只是创建一个产品,而抽象工厂或多或少是一堆工厂方法聚集在一起的家庭。
【解决方案2】:

这两种模式肯定是相关的!

模式之间的区别通常在于意图。

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

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

纯粹基于这些意图陈述(引自 GoF),我会说确实 Factory Method 在某种意义上是一个“退化的”Abstract Factory一个。

它们通常在实现上有所不同,因为 工厂方法抽象工厂 简单得多。

然而,它们在实现上也相关。正如 GoF 书中所述,

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

这个c2 wiki也有关于这个话题的一些有趣的讨论。

【讨论】:

  • 我既不理解评论也不理解反对意见。你能详细说明一下吗?
  • 嗯,答案在我看来是修辞……没有真正的具体例子……过于宽泛……
【解决方案3】:

似乎 OP 的(优秀)问题列表已被忽略。当前的答案仅提供重新定义的定义。因此,我将尝试简明扼要地解决最初的问题。

  1. 如果抽象工厂只有一个创作者和一个产品,那还是抽象工厂模式吗? (一个接口 创建家庭)

没有。一个抽象工厂必须创建一个以上的产品来制造一个“相关产品系列”。规范的 GoF 示例创建 ScrollBar()Window()。优点(和目的)是抽象工厂可以在其多个产品中强制执行一个共同的主题。

  1. 工厂方法具体创建者可以从接口创建还是必须从类创建? (课程推迟 子类的实例化)

首先,我们必须注意,当 GoF 撰写他们的书时,Java 和 C# 都不存在。 GoF 对术语 interface 的使用与特定语言引入的接口类型无关。因此,可以从任何 API 创建具体创建者。该模式的重点是 API 使用自己的工厂方法,因此只有一个方法的接口不能是工厂方法,也不能是抽象工厂。

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

根据上述答案,此问题不再有效;但是,如果您认为抽象工厂和工厂方法之间的唯一区别是创建的产品数量,请考虑客户如何使用这些模式。抽象工厂通常被注入其客户端并通过组合/委托调用。必须继承工厂方法。所以这一切都回到了旧的组合与继承的争论。

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

  1. 既然,只有一个方法的接口不能是工厂方法,就不能是抽象工厂我们该怎么办打电话给 只有一种方法的创建界面?

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

【讨论】:

  • 关于组合与继承,我一直在想:难道不能用工厂方法模式来组合吗?什么会阻止一个人为客户构建或注入正确的混凝土工厂?或者这已经超出了模式的范围?
  • @georaldc,来自 GoF(第 107 页)“Factory Method 允许类将实例化推迟到子类。”换句话说,Factory Method 根据定义使用继承。跨度>
【解决方案4】:

在我看来,这两种模式之间的细微差别在于适用性,如前所述,也在于Intent

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

抽象工厂

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

工厂方法

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

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

抽象工厂允许在一个子类中创建几种不同类型的实例,并在其不同的子类中具体化创建行为;通常,Factory 方法只声明创建一种类型的对象,可以根据子类化机制进行具体化。这就是区别。

通过总结。假设 Product 定义了创建对象的超类,ProductA 和 ProductB 是两个不同的子类。因此,Abstract Factory 方法将有两个方法,createProductA() 和 createProductB(),它们将在其特定的子类中详细说明(根据创建步骤):工厂子类详细说明 创建步骤 em> 用于创建对象的两个定义类。

根据上面的例子,Factory Method 的实现方式会有所不同,在尽可能多的工厂中抽象 ProductA 和 ProductB 的创建(每个 Factory 一个方法),以及创建步骤的进一步特化将在构建时委托给层次结构。

【讨论】:

    【解决方案5】:

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

    如果抽象工厂有不止一种方法来创建对象,那么它就是一个抽象工厂

    假设我创建了一个管理器来处理 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);
    }
    

    【讨论】:

      【解决方案6】:

      尽管 * 的人在其他帖子中类似地质疑这个问题已经很多年了(最早的到 2009 年),但我仍然找不到我想要的答案。


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

      • 意图:连贯性或“外观”:Abstract Factory 的意图是将一组具有相同样式的对象(例如外观和感觉相同的 UI 小部件、样式相同的汽车零件)分组, 来自同一操作系统的对象等)Abstract Factory 的许多示例都提到了关键短语“相同的外观和感觉”。
      • 对象组成一个更大的组对象:Abstract Factory 创建一个对象族,组成一个更大的组对象,而不是单个对象。
      • 稍后添加新样式:如果我们继续使用工厂方法并尝试在现有基础架构中添加一组新样式,那将是痛苦的。使用抽象工厂,我们只需创建一个新的具体工厂来实现抽象工厂类。

      反例是

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

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

      【讨论】:

        【解决方案7】:

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

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

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

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

        这些模式似乎相互配合。

        换句话说,抽象工厂专注于“什么”将被创建和工厂方法“如何”将被创建。

        【讨论】:

          【解决方案8】:

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

          哺乳动物工厂、鸟类工厂、鱼类工厂、爬行动物工厂。现在您已经拥有来自 AnimalSpeciesFactory 的单个工厂,它们使用工厂模式来创建特定的对象。例如,假设您从这个 AnimalFactory 获得了一个 ReptileFactory,那么您可以提供创建爬行动物对象,例如: 蛇、海龟、蜥蜴对象。

          【讨论】:

            【解决方案9】:
            /*
            //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;
            }
            
            */
            

            【讨论】:

              【解决方案10】:

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

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

              【讨论】: