类似于rime的rime::Class<factory type, product type>实现方式。

C++模板实现的通用工厂方法模式

1.工厂方法(Factory Method)模式

工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。

工厂方法模式结构示意图

工厂方法模式是简单工厂模式的衍生,解决了许多简单工厂模式的问题。首先完全实现‘开-闭 原则’,实现了可扩展。其次更复杂的层次结构,可以应用于产品结果复杂的场合。

工厂方法模式很好用,但在代码层面上,为每一个产品都编写一个对应的工厂,这无疑很麻烦,而且不同的Product要写不同Creator。想想你在写一个GUI库,基本控件为Widget类,由其派生下了TextBox,Button,Label等几十个控件,那你需要为这几十个控件分别编写对应的ConcreteCreator。天,这太麻烦了吧!而如果你还要写一个RPG小游戏,需要从Person类派生下如NPC,Hero,Emeny,Ally等又是十几个类,而且还要编写一个对应于Person的Creator....

2.模板实现工厂方法模式

面对这种类型造成的多态,C++模板就要出场了。现在情况是这样的,Product和ConcreteProduct都已经写好,我们要为其编写对应的工厂类。可以看出来,Product对应对Creator,ConcreteProduct对应于ConcreteCreator。也就是说,如果想编写通用的ConcreteCreator,就得将ConcreteProduct抽象,想编写通用的Creator,就得将Product抽象。而我们最后会将这2者都抽象了。

首先编写通用的ConcreteCreator

  1. // 具体工厂类
  2. // Product为抽象产品,ConcreteProduct为具体产品
  3. template<typename Product, typename ConcreteProduct>
  4. class ConcreteCreator
  5. {
  6. public:
  7. // 生产一个具体产品
  8. static Product* createProduct()
  9. {
  10. return new ConcreteProduct();
  11. }
  12. };

注意createProduct()是静态的,是因为该函数要被保存起来的,静态函数只需保存其函数指针即可,而普通的成员函数还要额外保存一个对象指针,这无疑更麻烦了。 也就是我们不需要这样用:

  1. ConcreteCreator<Product, ConcreteProduct> concreteCreator;
  2. Product* p = concreteCreator.createProduct();

只需要这样写:

  1. Product* p = ConcreteCreator<Product, ConcreteProduct>::createProduct();

下面是Creator的实现

  1. // 抽象工厂
  2. // Product为抽象产品
  3. template<typename Product>
  4. class Creator
  5. {
  6. // 单例实现
  7. public:
  8. static Creator& Instance()
  9. {
  10. static Creator<Product> instance;
  11. return instance;
  12. }
  13. private:
  14. Creator() {}
  15. ~Creator() {}
  16. Creator(Creator&);
  17. // 对外接口
  18. public:
  19. typedef Product* (*CreateProductDelegate)( ); // 生产产品的产品
  20. typedef std::map<std::string, CreateProductDelegate> MapRegisterCreatorItem;
  21. // 根据具体产品生成具体工厂
  22. // 并将具体产品注册进抽象工厂
  23. // ConcreteProduct为具体产品
  24. template<typename ConcreteProduct>
  25. void registerCreator(const std::string& _type)
  26. {
  27. mConcreteCreators[_type] = ConcreteCreator<Product, ConcreteProduct>::createProduct;
  28. }
  29. // 删除所有具体工厂
  30. void unregisterAllCreators()
  31. {
  32. mConcreteCreators.clear();
  33. }
  34. // 生产类型为_type的产品
  35. // 失败返回0
  36. Product* createProduct(const std::string& _type)
  37. {
  38. MapRegisterCreatorItem::iterator type = mConcreteCreators.find(_type);
  39. if (type != mConcreteCreators.end())
  40. {
  41. CreateProductDelegate create = type->second;
  42. if (create != 0)
  43. return create();
  44. }
  45. return 0;
  46. }
  47. private:
  48. MapRegisterCreatorItem mConcreteCreators; // 保存所有注册过的具体产品
  49. };

下面来简单解释一下上面的代码。

首先Creator实现了单例模式,这只是为了方便使用,你也可以不实现为单例。

Creator里面保存了所有注册过的具体工厂,具体工厂在注册时被构建,每个具体工厂对应一个名字(string类型)。

createProduct即为工厂方法,外部通过此接口创建产品,创建时仅需提供具体工厂的名字即可。

我们以RPG游戏那个作为例子。要创建一个Person的Creator,可以这样写

  1. typedef Creator<Person> PersonCreator;
  2. PersonCreator& factory = PersonCreator::Instance();
  3. factory.registerCreator<Person>("Person");
  4. factory.registerCreator<Hero>("Hero");
  5. factory.registerCreator<NPC>("NPC");

这样即完成了注册过程,你可以继续为其他类型注册具体工厂。

要创建一个NPC,可以这样写

  1. Person* npc = factory.createProduct("NPC");

3.优缺点

此方法的优点很明显,就是用起来很方便。由于Creator支持不同类型,你不要为不同的产品编写不同的Creator。而且其提供了注册具体工厂的方法,你仅需要写一行代码即可为具体产品生成具体的工厂,而不需要编写专门的类。

而且其注册过程是可以在运行时修改的,也就是说你可以在运行时动态地注册或反注册具体工厂,这样灵活性就很大了。

缺点的话就是不支持构造函数参数,也就是说在创建产品时不支持参数。当然可以为不同数量参数编写具体的模板Creator。但其实个人并不提倡提供无参构造函数。我认为像这类产品类,都应该提供一个无参的构造函数版本,然后提供get,set函数来修改内部成员变量。

c++模板实现抽象工厂的更多相关文章

  1. 设计模式之美:Abstract Factory(抽象工厂)

    索引 别名 意图 结构 参与者 适用性 缺点 效果 相关模式 命名约定 实现 实现方式(一):使用 Factory Method 来实现 Abstract Factory. 实现方式(二):使用 Pr ...

  2. 5. 星际争霸之php设计模式--抽象工厂模式

    题记==============================================================================本php设计模式专辑来源于博客(jymo ...

  3. 利用CodeSmith生成抽象工厂步骤

    其实CodeSmith挺好的,帮我们主动生成不少代码,并且代码质量不错,下面就来介绍一下利用CodeSmith生成抽象工厂步骤 打开codesmith模板的buildall 注意path的设置,因为后 ...

  4. Java设计模式系列-抽象工厂模式

    原创文章,转载请标注出处:https://www.cnblogs.com/V1haoge/p/10755412.html 一.概述 抽象工厂模式是对工厂方法模式的再升级,但是二者面对的场景稍显差别. ...

  5. 第20月第29天 cocoa抽象工厂 cocoapods组件化 cocoapods升级

    1. 在 Cocoa Touch 框架中,类簇是抽象工厂模式在 iOS 下的一种实现,以 NSArray 举例,将原有的 alloc+init 拆开写: id obj1 = [NSArray allo ...

  6. 设计模式C++学习笔记之七(AbstractFactory抽象工厂模式)

      抽象工厂,提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类.对于工厂方法来说,抽象工厂可实现一系列产品的生产,抽象工厂更注重产品的组合. 看代码: 7.1.解释 main(),女 ...

  7. 【设计模式】 模式PK:抽象工厂模式VS建造者模式

    1.概述 抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品:具有不同分类维度的产品组合,采用抽象工厂模式则是不需要关心构建过程,只关心什么产品由什么工厂生产即可.而建造者模式则是要求按 ...

  8. 设计模式C#合集--抽象工厂模式

    抽象工厂,名字就告诉你是抽象的了.上代码. public interface BMW { public void Drive(); } public class BMW730 : BMW { publ ...

  9. PHP设计模式(三)抽象工厂模式(Abstract Factory For PHP)

    一.什么是抽象工厂模式 抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象 ,而且使用抽象工厂模式还要满足以下条件: 系统中有多个产品族,而系统一次只可能消费其中一族产品. 同 ...

随机推荐

  1. ###STL学习--函数对象

    点击查看Evernote原文. #@author: gr #@date: 2014-08-13 #@email: forgerui@gmail.com 在stl中,函数对象被大量地使用,用以提高代码的 ...

  2. HDU 4430 Yukari's Birthday(二分)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4430 题目大意:给定n个蜡烛,围绕蛋糕的中心插同心圆,从里往外分别是第1圈.第2圈....第r圈,第 ...

  3. [翻译][MVC 5 + EF 6] 9:异步和存储过程

    原文:Async and Stored Procedures with the Entity Framework in an ASP.NET MVC Application 1.为什么使用异步代码: ...

  4. CentOS下Apache+SVN+LDAP的安装与配置

    上班接近4个月了,在公司做配置管理工程师,主要是在Linux下对公司的源代码以及项目发布进行管理.4个月接触了好多新知识,也对各种工具的集成使用搞得云里来雾里去的,所以打算自己搭建一套环境,进行测试. ...

  5. Cloudcraft: 云架构图形可视化(智能AWS图表)

    Cloudcraft: 云架构图形可视化(智能AWS图表) 2016.09.11 官方网站: https://cloudcraft.co/ Cloudcraft是一个Web应用,用图形表示各种AWS服 ...

  6. jquery checkbox 选中 全选 插件

    checkbox  选中 全选 在项目中经常用到,但是不同的程序员写出的东西各有差异,在此整合了jquery checkbox插件,用起来很方便,也总结了我们项目中通常会出现问题的地方,一行代码搞定. ...

  7. .net面试题( 转)

    描述线程与进程的区别? 什么是Windows服务,它的生命周期与标准的EXE程序有什么不同 Windows上的单个进程所能访问的最大内存量是多少?它与系统的最大虚拟内存一样吗?这对于系统设计有什么影响 ...

  8. 【转】C#.net拖拽实现获得文件路径

    C#.net拖拽实现获得文件路径 作者Attilax ,  EMAIL:1466519819@qq.com 思路: 通过DragEnter事件获得被拖入窗口的“信息”(可以是若干文件,一些文字等等), ...

  9. oracle11g 表或视图连接时有可能发生的问题

    ---------背景--------- oracle11g 有2个视图,都有一个id字段,且id字段的值相同 例如:id都有 A01 ,A02 ,A03 --------问题--------- 把2 ...

  10. Control character in cookie value, consider BASE64 encoding your value , java操作cookie遇到中文会报错的解决方案

    项目当中用到cookie保存中文,但是会报如下错误: Control character in cookie value, consider BASE64 encoding your value 大概 ...