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

注意: 问题在文章的最后。

我已经阅读了关于 抽象工厂与工厂方法的其他堆栈溢出线程。我明白每个模式的意图。然而,我不清楚的定义。

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

相比之下,抽象工厂 提供一个用于创建 有亲属关系或受扶养人的家庭 对象,而不指定它们的 具体类别。

John Feminella

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

注:

  • 图表来自 Www.yuml.com,所以他们不是完美的定位。但它是一个免费的服务:)。
  • 图表可能并不完美,我还在学习 卧槽的设计模式。

工厂方法:

Factory Method

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

Abstract Factory (only 1 member)

抽象工厂(更多会员) :

alt text

问题:

  1. 如果 抽象工厂只有一个创造者和一个产品,它仍然是 抽象工厂模式吗
  2. 可以从接口创建 工厂法具体的创建者还是必须从类中创建
  3. 如果抽象工厂只能有一个创建者和一个产品,那么 抽象工厂工厂法之间的唯一区别是前者的创建者是一个接口,而后者的创建者是一个类吗?
67541 次浏览

这两种模式肯定是有联系的!

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

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

抽象工厂意图是“提供创建相关或依赖对象家族的接口,而不指定它们的具体类。”

纯粹基于这些意图陈述(引自 GoF) ,我想说的是,实际上 工厂法在某种意义上是一个“退化的”抽象工厂,它只有一个家族。

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

然而,它们在实现中也是相关的,

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

这个 C2维基也有一些关于这个主题的有趣讨论。

希望这个能帮上忙。它描述了各种类型的工厂。我用 以头为先的设计模式的书作为参考。我用 美味的我做了图解。

静电工厂

是一个具有静态方法的类,用于生成 Product 的各种子类型。

Static Factory

简单工厂

是一个可以生成 Product 的各种子类型的类。(比静电工厂好。当添加新类型时,基础 Product 类不需要更改,只需更改 SimpleFactory 类)

Simple Factoryt

工厂法

包含一个生成与其类型相关的产品类型的方法。(它比 Simple Factory 更好,因为类型延迟到子类。)

Factory Method

抽象工厂

生成相关的类型族。它明显不同于 Factory Method,因为它生成的类型有多个方法。(这个比较复杂,请参考下一个图表,以获得更好的实际例子)。

Abstract Factory

来自.NETFramework 的示例

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

Abstract Factory From .NET Framework

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

如果抽象的 Factory 有多个方法来创建对象,那么它将是一个 抽象工厂

假设我创建了一个 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);
}

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

第二种方法使用已经创建的对象(系列)来实现工厂方法接口。然后,工厂方法创建与原始对象相关的特定实例,而不管它是哪个对象。

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

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

看起来这些模式对每一个都是合作的。

换句话说,抽象工厂的重点是“什么”将被创建和工厂方法“如何”它将被创建。

在我看来,这两种模式之间的细微差别在于 适用性,因此,正如前面所说,在 意图

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

抽象工厂

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

工厂法

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

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

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

通过总结。假设 Product 定义了创建对象的超类,ProductA 和 ProductB 是两个不同的子类。因此,抽象工厂方法将有两个方法,createProductA ()和 createProductB () ,这两个方法将在其特定的子类中具体化(在创建步骤方面) : 工厂子类为创建中的两个已定义的对象类具体化 创作步骤

根据上面的例子,工厂方法的实现将会有所不同,抽象出 ProductA 和 ProductB 在同样多个工厂中的创建(每个工厂一个方法) ,并且 创作步骤的进一步专门化将在构建时委托给层次结构。

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

哺乳动物工厂,鸟类工厂,鱼类工厂,爬行动物工厂。现在您已经有了 AnimalSpeciesFactory 中的一个工厂,它们使用工厂模式来创建特定的对象。例如,假设您从 AnimalFactory 获得了一个 ReptileFactory,然后您可以创建爬行动物对象,比如: 蛇,乌龟,蜥蜴之类的东西。

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


所以我花了几个小时的时间通过网络进行研究,回顾了这些例子,得出了这个结论,抽象工厂和工厂方法的主要区别是

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

相反的例子是

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

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

看起来 OP 列出的(优秀的)问题被忽略了。目前的答案只是提供了重复的定义。因此,我将试图简明扼要地回答最初的问题。

  1. 如果 抽象工厂只有一个创建者和一个产品,那么它仍然是 抽象工厂模式吗 创建家庭)

没有。抽象工厂 必须的创建一个以上的产品,使“相关产品家族”。规范的 GoF 示例创建 ScrollBar()Window()。其优点(和用途)是抽象工厂可以在其多个产品之间强制执行一个公共主题。

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

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

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

但是,如果您认为抽象工厂和工厂方法之间的唯一区别是创建的产品数量,那么请考虑客户端如何使用这些模式。抽象工厂通常被注入其客户端并通过组合/委托调用。必须继承工厂方法。因此,这一切都回到了旧的组合与继承的争论。

但这些答案引发了第四个问题!

  1. 因为,一个只有一个方法的接口不能是 < strong > Factory Method ,就像它不能是 < strong > 摘要 Factory 一样,我们叫它什么 只有一种方法的创建接口?

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

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

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

/*
//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;
}


*/