【创建型】Abstract Factory模式 & Factory Method模式
本文主要介绍简单工厂模式与抽象工厂模式。以下如有叙述不当之处,欢迎批评指正,欢迎交流探讨。
一:简单工厂模式
在23种设计模式中,简单工厂模式其实是不在列的,但理解该模式对于抽象工厂模式的思想理解是有帮助的。就纯粹从字面上理解,简单工厂模式就是一种简单版的工厂模式。在日常开发过程中,相信绝大多数人都使用过。它主要是在设计上将一种产品或一系列具有相互关系的产品的创建工作,由专门设计好的类(即:工厂类)统一提供相关接口来完成。这样,在上下文中所面对的产品类的创建工作将是“隐式的”,不会直接产生对某个或某些具体产品类的依赖。
简单工厂模式是指为创建一系列相关或相互依赖的对象提供接口,使得上下文脱离对具体产品类的直接依赖。类关系图参考如下:
根据上面关系图,模式的编码结构参考如下:
namespace simple_factory
{
/******************************************************************************
* create : (jacc.kim) [5-15-2016]
* summary : 产品A
******************************************************************************/
class IAbstractProductA
{
public:
enum class eType {};
};//class IAbstractProductA class ConcreteProductA1 : public IAbstractProductA {};
class ConcreteProductA2 : public IAbstractProductA {}; /******************************************************************************
* create : (jacc.kim) [5-15-2016]
* summary : 产品B
******************************************************************************/
class IAbstractProductB
{
public:
enum class eType {};
};//class IAbstractProductB class ConcreteProductB1 : public IAbstractProductB {};
class ConcreteProductB2 : public IAbstractProductB {}; /******************************************************************************
* create : (jacc.kim) [5-15-2016]
* summary : 简单工厂
******************************************************************************/
class SimpleFactory
{
public:
IAbstractProductA* createProductA(const IAbstractProductA::eType) {} // 参数可选
IAbstractProductB* createProductB(const IAbstractProductB::eType) {} // 参数可选
};//class SimpleFactory }//namespace simple_factory
简单工厂模式编码结构参考
简单工厂的一个明显的缺点是一旦具体产品的种类变得越来越多时,则工厂将会变得庞大且复杂,后期维护将会越来越累。
二:抽象工厂模式
与简单工厂模式类似,抽象工厂模式类似也是为创建一系列相关或相互依赖的产品提供统一的接口,并且不需要指定具体的产品类。
与简单工厂模式不同的是不同系列类型的产品是由具体的工厂类来负责创建,从而避免简单工厂模式中,工厂类的实现分支过度复杂的问题。类关系图参考如下:
由图知,不同的产品系列将是由不同的具体工厂类来实例化。模式编码结构参考如下:
namespace abstract_factory
{
/******************************************************************************
* create : (jacc.kim) [5-16-2016]
* summary : 产品A
******************************************************************************/
class IAbstractProductA
{
public:
enum class eType {};
};//class IAbstractProductA class ConcreteProductA1 : public IAbstractProductA {};
class ConcreteProductA2 : public IAbstractProductA {}; /******************************************************************************
* create : (jacc.kim) [5-16-2016]
* summary : 产品B
******************************************************************************/
class IAbstractProductB
{
public:
enum class eType {};
};//class IAbstractProductB class ConcreteProductB1 : public IAbstractProductB {};
class ConcreteProductB2 : public IAbstractProductB {}; /******************************************************************************
* create : (jacc.kim) [5-16-2016]
* summary : 工厂
******************************************************************************/
class IAbstractFactory
{
public:
IAbstractProductA* createProductA(/*const IAbstractProductA::eType*/) {} // 参数可选
IAbstractProductB* createProductB(/*const IAbstractProductB::eType*/) {} // 参数可选
};//class IAbstractFactory class ConcreteFactory1 : public IAbstractFactory {
public:
IAbstractProductA* createProductA(/*const IAbstractProductA::eType*/) { return new (std::nothrow) ConcreteProductA1(); }
IAbstractProductB* createProductB(/*const IAbstractProductB::eType*/) { return new (std::nothrow) ConcreteProductB1(); }
};//class ConcreteFactory1 class ConcreteFactory2 : public IAbstractFactory {
public:
IAbstractProductA* createProductA(/*const IAbstractProductA::eType*/) { return new (std::nothrow) ConcreteProductA2(); }
IAbstractProductB* createProductB(/*const IAbstractProductB::eType*/) { return new (std::nothrow) ConcreteProductB2(); }
};//class ConcreteFactory2 }//namespace abstract_factory
抽象工厂模式编码结构参考
三:工厂方法模式
与抽象工厂模式类似,也是为了解决简单工厂模式中因具体产品种类过多而导致工厂的负担过重的问题。工厂方法模式是指:为创建具体产品对象定义统一的接口,并且接口的具体实现是由具体的子类来实现。即:具体的产品的实例化由对应的具体工厂来负责。形象点说就是,某个具体的工厂子类,负责创建对应的具体的产品对象。类关系图参考如下:
工厂方法模式编码结构参考如下:
namespace factory_method
{
/******************************************************************************
* create : (jacc.kim) [5-16-2016]
* summary : 产品
******************************************************************************/
class IAbstractProduct {};
class ConcreteProduct1 : public IAbstractProduct {};
class ConcreteProduct2 : public IAbstractProduct {}; /******************************************************************************
* create : (jacc.kim) [5-16-2016]
* summary : 工厂
******************************************************************************/
class IAbstractFactory
{
public:
virtual IAbstractProduct* createProduct() = ;
};//class IAbstractFactory class ConcreteFactory1 : public IAbstractFactory
{
public:
virtual IAbstractProduct* createProduct() override {
return new (std::nothrow) ConcreteProduct1();
}
};//class ConcreteFactory1 class ConcreteFactory2 : public IAbstractFactory
{
public:
virtual IAbstractProduct* createProduct() override {
return new (std::nothrow) ConcreteProduct2();
}
};//class ConcreteFactory2 }//namespace factory_method
工厂方法模式编码结构参考
四:几种模式总结
a) 简单工厂模式与抽象工厂模式均可创建一系列相关或相互依赖的产品,产品的类型可以不同。但抽象工厂模式的工厂类中,创建具体产品对象时,是由相关的派生类工厂对象来负责。而简单工厂模式则是通过条件分支来分别处理;
b) 工厂方法模式重点是负责同一类型系列的产品,产品类型会比较单一;
c) 抽象工厂模式与工厂方法模式,在工厂类层面上,各个具体派生类的职责相比简单工厂模式会更加的清晰、明确;
d) 不论是以上哪种模式,最终的目的都只有一个:保证客户端(即:以上图中的 Client)层面上的逻辑框架结构不需要修改就可以轻松切换各种具体产品对象的使用,而且最为最关键的是Client还不需要直接依赖于这些具体的产品对象类。
五:高级话题
目前比较主流的几种设计语言中,如Java、C#这类较C++晚出现的语言来说,像垃圾回收这样的机制,相信众多程序猿都会很自豪地说这么一句话:自动有了垃圾回收后,“妈妈”再也不用担心我写的代码会有内存泄漏了。其实这些语言还有一样利器,也是非常屌的,就是反射。相信许多c++程序猿都会经常做这么一件事,像上面工厂模式中,经常会不断地if else或case各种情况,然后创建各种对应的子产品对象。试想下,如果日后再新添加产品时,就得重新改一次工厂类的实现。再加一种产品,再改一次,........一直如此维护下去。而且一般项目中,可能会有非常非常多的工厂类,那维护就不是一般的累了。因此有经验的C++程序员此时会立刻想到反射。
如果有人对RTTI产生过好奇的话,可能就会想到这么一个问题:我们平时写的类啊什么的,是保存在一个个文件中的,可为什么编译器就是能够把它们识别出来,并让程序正常有序地工作下去而不会出错?有兴趣的同学可以上网找找这方面的资料,总是有许多的。在此,主要是想说说C++中的“反射”(因为此处讲反射与本博客的主题算是有一定的关系)。C++虽说是一门非常高级的高级语言,但它却没有反射机制(不但没有反射机制,就连垃圾回收机制也是没有的)。可幸的是,C++也是一门威力十分强大的语言。就算没有,许多前辈们也总能想出办法来实现它们。就如没有垃圾回收,但我们可以实现智能指针,反射也一样。
要实现反射,则首先必需要解决的一个问题是:类型 -------- 任意类型。我们不可能只为某一个类(系列)实现反射,那样根本就没有通用性,代码就不可利用,就没有任何大的意义。而C++中,类型无关性的编码,很自然的会想到template,思路到这,相信许多人一下子就豁然开然了。因此最基本的实现编码结构如下:
/******************************************************************************
* create : (jacc.kim) [1-14-2016]
* summary : class GFReflector.custom product reflector.
******************************************************************************/
template<typename TIDX, typename TProduct>
class GFReflector
{
public:
// create a new concrete produce instance.
static TProduct* createInstance(const TIDX& id); };//template<typename TIDX, typename TProduct> class GFReflector
Reflector编码基本结构参考
再接下来要做什么?很明显为了根据TIDX类型,我们要能够创建出对应的对象实例。而这部分的工作,可以转交给用户去实现(也必需交由用户去实现)。于是我们需要一张映射表,要能够根据具体TIDX,映射到如何创建出对应对象实例的表。此时自然就会想到函数指针、仿函数、function等等技术手段。因此,改进后的编码结构大致如下:
/******************************************************************************
* create : (jacc.kim) [1-14-2016]
* summary : class GFReflector.custom product reflector.
******************************************************************************/
template<typename TIDX, typename TProduct>
class GFReflector
{
public:
typedef typename TProduct* (*fpProductCreator)();
typedef typename std::function<TProduct*()> GFProductCreator; // create a new concrete produce instance.
static TProduct* createInstance(const TIDX& id); public:
GFReflector();
GFReflector(const TIDX& id, fpProductCreator fpCreator);
/*virtual */~GFReflector(); private:
GFReflector(const GFReflector&) DELETE_METHOD;
GFReflector& operator=(const GFReflector&) DELETE_METHOD; private:
typedef typename std::map<TIDX, GFProductCreator> GFCreatorMap; private:
static GFCreatorMap& getAllCreator(); };//template<typename TIDX, typename TProduct> class GFReflector
Reflector编码结构参考
最后,用户在使用上只需要简简单单地进行注册与反注册即可。比如(用法示例):
// 示例一:
typedef nsgf::GFReflector<eGHEventType, IGHEvent> TEventReflector; TEventReflector::registe(eGHEventType::eComplex, [](){ return GFNEW CGHComplexEvent(); }); // 示例二:
typedef nsgf::GFReflector<eGHSkillType, IGHSkill> TSkillReflector; TSkillReflector::registe(eGHSkillType::eRoleSkill, [](){ return GFNEW CGHRoleSkill(); });
反射用法示例参考
有了以上的反射机制,我们还可以实现一个通用的工厂类。以下是个人先前搭的一个框架中设计的一个通用工厂类的主要编码结构(仅供参考):
/******************************************************************************
* create : (jacc.kim) [1-14-2016]
* summary : class GFProductFactory.custom product factory.
******************************************************************************/
template<typename TIDX, typename TProduct>
class GFProductFactory
{
public:
typedef std::function<void()> GFRegister;
typedef typename std::function<void(TProduct*)> GFProductDestroyer; public:
// clear all instances of cache.(remove from memory really).
void clearAllInstance(); public:
// create a new concrete produce instance.
virtual TProduct* createInstance(const TIDX& id); // (force) borrow a concrete produce instance.
virtual TProduct* borrowInstance(const TIDX& id); // return a concrete produce instance that can generate with borrowInstance() or createInstance() method.
virtual bool returnInstance(const TIDX& id, TProduct* pProduct); public:
virtual ~GFProductFactory(); // some code here........ };//template<typename TIDX, typename TProduct> class GFProductFactory NSGF_END
通用工厂类的主要编码结构参考
该通用工厂类不但支持一般工厂模式的功能,还可以支持Cache功能。即:有些功能中,因为对象使用十分频繁,如果每次创建用完后就删除掉,那样将是十分耗性能的。比如:在游戏AI中,肯定会有大量的对象,Buff,技能........,此时cache功能就十分有用。从上面的通用工厂类设计中也可以看出,支持createInstance(); 也支持borrowInstance();与returnInstance();一般情况下,后面两个接口是成对使用的。当然如果是由createInstance()创建出来的对象也return给通用工厂类,Ok,完全没问题。因为它是一个简单意义上的Cache,没有任何其他逻辑上的约束。因此,使用上十分方便。其实有这样的一个通用工厂类,在一定意义上,可以完全取代 Flyweight 设计。
【创建型】Abstract Factory模式 & Factory Method模式的更多相关文章
- [Python编程实战] 第一章 python的创建型设计模式1.1抽象工厂模式
注:关乎对象的创建方式的设计模式就是“创建型设计模式”(creational design pattern) 1.1 抽象工厂模式 “抽象工厂模式”(Abstract Factory Pattern) ...
- 行为型设计模式之模板方法(TEMPLATE METHOD)模式 ,策略(Strategy )模式
1 模板方法(TEMPLATE METHOD)模式: 模板方法模式把我们不知道具体实现的步聚封装成抽象方法,提供一些按正确顺序调用它们的具体方法(这些具体方法统称为模板方法),这样构成一个抽象基类.子 ...
- C#设计模式--工厂模式(创建型模式)
一.简单工厂模式(UML类图): 核心类代码: public class Calc { public double NumberA { get; set; } public double Number ...
- Template Method模式和Strategy模式[继承与委托]
继承 program by difference. 通过继承,可以建立完整的软件结构分层.其中每一层都可以重用该层次以上的Code. 过度使用继承的代价是巨大的.应使用组合或者委托来替代继承. Tem ...
- 设计模式(3)-对象创建型模式-Abstract Factory模式
1.对象创建型模式 1.3 Abstract Factory模式 1.3.1 需求 在下面情况能够使用Abstract Factory模式: • 一个系统要独立于它的产品的创建. ...
- 设计模式02: Abstract Factory 抽象工厂(创建型模式)
Abstract Factory 抽象工厂(创建型模式) 常见的对象创建方法: //创建一个Road对象 Road road=new Road(); new的问题: -实现依赖 ...
- JAVA设计模式(01):创建型-工厂模式【工厂方法模式】(Factory Method)
简单工厂模式尽管简单,但存在一个非常严重的问题.当系统中须要引入新产品时,因为静态工厂方法通过所传入參数的不同来创建不同的产品,这必然要改动工厂类的源码,将违背"开闭原则".怎样实 ...
- 5、抽象工厂 abstract factory 将关联组件组成产品 创建型模式
趁热打铁,紧跟着上一节的工厂方法模式.这一节介绍一下抽象工厂模式,以及分析俩个模式的不同 1.何为抽象模式? 抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他 ...
- 3.Factory Method 工厂方法模式(创建型模式)
1.定义: 定义一个用于创建对象的接口,让子类决定实例化哪一个类.Factory Method使得一个类的实例化延迟到子类. 2.实现代码如下: /// <summary> /// 工厂方 ...
- C#设计模式之二工厂方法模式(Factory Method Pattern)【创建型】
一.引言 在上一篇文章中我们讲解了过渡的一种模式叫做[简单工厂],也有叫[静态工厂]的,通过对简单工厂模式得了解,我们也发现了它的缺点,就是随着需求的变化我们要不停地修改工厂里面的方法的代码,需求变化 ...
随机推荐
- 【HDOJ】1063 Exponentiation
这道题目莫名其妙的wa,又莫名其妙的过了. import java.util.Scanner; import java.math.BigDecimal; public class Main { pub ...
- C++ BigInteger 大整数类模板(转)
#include <deque> #include <vector> #include <iostream> #include <string> #in ...
- 将银行读卡设备读取到的身份证头像Bitmap属性转换成路径
需求是这样的,在项目开发的时候要求读取身份证,读到身份证的所有信息(信息里面包括头像属性,类型是Bitmap的).然后服务器要求我传过去的头像信息是String类型的Uri路径. 这是读卡器读到的身份 ...
- Delphi String 与wideString 的完美转换
一般来说,String与widestring 的转换是系统自动进行的,但是,考虑如下字符串 s:=#2+#3+#0+#10+#0+#1+#164+#59;,显然S的长度为8,然后执行如下代码 var ...
- Purchase Document Open Interface(PDOI)
PO模块也有自己的接口表,多用于把其他业务系统在Oracle EBS系统生成采购订单记录. Table Name Description Type PO_HEADERS_INTERFACE This ...
- Linux/UNIX套接字连接
套接字连接 套接字是一种通信机子.凭借这样的机制.客户/server系统的开发工作既能够在本地单机上进行.也能够夸网络进行. 套接字的创建和使用与管道是有差别的.由于套接字明白地将客户和server区 ...
- Java 异常处理的误区和经验总结--转载
本文着重介绍了 Java 异常选择和使用中的一些误区,希望各位读者能够熟练掌握异常处理的一些注意点和原则,注意总结和归纳.只有处理好了异常,才能提升开发人员的基本素养,提高系统的健壮性,提升用户体验, ...
- Spring AOP 实现原理与 CGLIB 应用--转
AOP(Aspect Orient Programming),作为面向对象编程的一种补充,广泛应用于处理一些具有横切性质的系统级服务,如事务管理.安全检查.缓存.对象池管理等.AOP 实现的关键就在于 ...
- 用switch判断月份的练习
import java.util.Scanner; public class SwitchTest01 { public static void main(String[] args) { Syste ...
- spring06Aop
1.实现前置增强 必须实现接口MethodBeforeAdvice接口 创建对应的文件 public interface Animal {//主业务接口 void eat(); //目标方法 void ...