c++11设计模式 工厂模式 泛型抽象

当程序中许多的类需要使用共同的接口时,可以考虑工厂模式。传统的抽象工厂实现先定义用于创建不同产品的接口, 但将实际的创建工作留给了派生的具体工厂类。 每个工厂类型都对应派生出的不同产品。本文的工厂模式可以实现不同抽象工厂的异类集合,避免了定义多个工厂类。并且可以传递不同参数来构造生产不同类型的产品。

#include <memory>
#include <map>
#include <unordered_map>
#include <iostream>

template<typename AbsProduct, typename ProductKey=std::string, typename...Args>
class Factory {
 public:
    static Factory &GetInstance() {
        static Factory factory;
        return factory;
    }

    template<typename Product>
    void Register(const ProductKey& key) {
        factory_map_.emplace(key, [](Args...args)->AbsProduct*{return new Product(args...);});
    }

    std::shared_ptr<AbsProduct> MakeProduct(const ProductKey& key, Args&&...args) {
        if (factory_map_.find(key) != factory_map_.end()) {
            return std::shared_ptr<AbsProduct>(factory_map_[key](args...));
        } else {
            return std::shared_ptr<AbsProduct>();
        }
    }

 private:
    using CreatProduct = std::function<AbsProduct*(Args...)>;
    std::unordered_map<ProductKey, CreatProduct> factory_map_;
};

Factory类有三个模板参数,分别是
AbsProduct
抽象产品类,通过传递不同的抽象产品类可以获取对应的抽象工厂类,从而不用像传统的抽象工厂实现中需要定义不同的抽象工厂。

ProductKey
具体产品的键值,用于表示不同的具体产品。默认为std::string。

…Args
可变参数,由于不用的具体产品构造函数的参数可能不相同,可以通过可变参数传递参数来构造。

成员:
CreatProduct
表示具体产品的构造方法。

factory_map_
是一个unordered_map,用于保存具体产品的构造方法,通过ProductKey区别。

GetInstance
用于获取Factory单例。

Register
用于注册具体的产品,它的模板参数Product即为具体产品类型,函数参数ProductKey是具体产品的标识,这里作为factory_map_的key,value是lambda表达式,用来创建具体产品。

MakeProduct
用于创建具体的产品类型对象,为了避免内存泄露问题,这里使用智能指针进行返回。函数的参数ProductKey是具体产品的键值,Args是可变参数,用于传递参数给具体产品的构造函数。先搜索factory_map_中是否已经保存了具体产品的构造方法,存在则直接调用对应lamda表达式构造;没有则直接构造一个抽象类对象,最后保存到智能指针中返回。


测试:

class AbsProductA {
 public:
    AbsProductA() {}
    virtual void Show()=0;

 protected:
    int a_;
    int b_;
};

class PA1 : public AbsProductA {
 public:
    PA1(int a) { a_ = a; };
    void Show() {std::cout << "PA1" << std::endl;};
};

class PA2 : public AbsProductA {
 public:
    PA2(int b) { b_ = b; };
    void Show() {std::cout << "PA2" << std::endl;};
};

class AbsProductB {
 public:
    AbsProductB() {}
    virtual void Show()=0;

 protected:
    std::string str_;
};

class PB1 : public AbsProductB {
 public:
    PB1(std::string str) { str = str_; };
    void Show() {std::cout << "PB1" << std::endl;};
};


int main() {
    std::string pa1_key = "pa1";
    std::string pa2_key = "pa2";
    auto factory_a = Factory<AbsProductA, std::string, int>::GetInstance();
    factory_a.Register<PA1>(pa1_key);
    factory_a.Register<PA2>(pa2_key);
    auto pa1_ptr = factory_a.MakeProduct(pa1_key, 1);
    pa1_ptr->Show();
    auto pa2_ptr = factory_a.MakeProduct(pa2_key, 2);
    pa2_ptr->Show();

    std::string pb1_key = "pb1";
    auto factory_b = Factory<AbsProductB, std::string, std::string>::GetInstance();
    factory_b.Register<PB1>(pb1_key);
    auto pb1_ptr = factory_b.MakeProduct(pb1_key, "pb");
    pb1_ptr->Show();

    return 0;
}

输出

PA1
PA2
PB1
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
作者:张耀仁(是code不是书) 出版社:中国铁道出版社 出版日期:2006-07 内容简介 本书包含所有重要的有关C++程序设计的知识,除了入门的基础知识之外,对较深入的内容也作了讲解,例如对VPTR和VTABLE都有精彩的说明。本书提供了极佳的学习步调和连贯的先后次序,叙述方式主线明显,使读者不会为枝节所扰而混淆了学习主线,以达到良好的学习效果。. 本书内容不仅涵盖了最基本的语法,也深入探讨了面向对象的主要思想,可为C++程序设计语言的学习打下坚实基础,不仅适合程序设计语言的初学者,也适合使用C++程序设计语言开发应用软件的工程师。... 编辑推荐 为了符合读者的需要,本书采取简明易懂的叙述方式,并通过精心安排的大量例题,使每学完一章都可以编写出相应的程序。例如,如何避免语法和语义的错误,如何使用预处理指令,如何产生随机数,如何估计程序运算所花费的时间,如何从现有文件读取数据,如何将执行结果存盘,如何使用对象来仿真实际的互动关系等常遇到的编程问题,都可在本书内找到答案。本书配盘内附超过180个完整的范例程序,全部经过符合最新ANSI/ISO标准的C++编译器测试,并能正确执行。 目录 PART I C++程序语言基础 第1章 基本概述 1.1 计算机的发明与演进 1.2 计算机的基本结构 1.3 冯·诺依曼结构 1.4 计算机内部的数据表达方式 1.5 软件 1.6 程序语言(Programming Ianguages 1) 1.7 c++程序语言 1.8 程序语言的演变 1.9 本章重点 1.10 本章练习 第2章 C++的基本语法和使用环境 2.1 基本程序开发步骤 2.2 第一个完整的C++程序 2.3 延迟DOS窗口界面自动关闭的方法 2.4 Borland C++编译器的取得和安装使用 2.5 Visual c++.NET程序开发步骤 2.6 第二个C++程序 2.7 C++标识符的命名规则 2.8 本章重点 2.9 本章练习 第3章 基本数据类型 3.1 整数和浮点数 3.2 变量和常量 3.3 算术运算 3.4 标准数学函数的运算 3.5 逻辑值及其运算 3.6 字符与字符串 3.7 位处理运算 3.8 常犯的错误 3.9 本章练习 第4章 分支 4.1 算法的描述方式 4.2 变量的适用范围 4.3 if.else语句 4.4 嵌套if.else语句 4.5 switch语句 4.6 条件运算符 4.7 goto无条件跳转语句 4.8 常犯的错误 4.9 本章重点 4.1 0本章练习 第5章 循环 5.1 循环指令的种类 5.2 while循环 5.3 continue和break 5.4 do.while循环 5.5 for循环 5.6 嵌套循环 5.7 常犯的错误 5.8 本章重点 5.9 本章练习 第6章 函数 6.1 函数的基本概念 6.2 以引用的方式调用 6.3 inline函数 6.4 变量的适用范围和生存期间 6.5 常犯的错误 6.6 本章重点 6.7 本章练习 第7章 数组 7.1 一维数组 7.2 将数组当成函数的参数 7.3 二维数组 7.4 将二维数组当成函数的参数 7.5 常犯的错误 7.6 本章重点 7.7 本章练习 PART II 高级C++程序设计语言 第8章指针 8.1 内存地址与指针 8.2 指针与引用 8.3 数组与指针的代数计算 8.4 指针参数 8.5 函数指针 8.6 动态内存分配 8.7 常犯的错误 8.8 本章重点 8.9 本章练习 第9章 字符串 9.1 字符串的基本概念 9.2 字符串的输入与输出 9.3 字符串的处理 9.4 字符串的指针数组 9.5 字符串处理在编码上的应用 9.6 常犯的错误 9.7 本章重点 9.8 本章练习 第10章 函数的高级应用 10.1 函数的重载 10.2 参数的默认值 10.3 模板函数 10.4 随机数的取得 10.5 递归函数 10.6 排序与搜索 10.7 常犯的错误 10.8 本章重点 10.9 本章练习 第11章 预处理命令 11.1 预处理器 11.2 使用#define进行文字取代 11.3 使用#define设置宏命令 11.4 条件编译 11.5 其他与编译器有关的预处理命令 11.6 常犯的错误 11.7 本章重点 11.8 本章练习 第12章 数据流与文件的存取 12.1 数据流 12.2 文件的存取 12.3 文件的存取模式 12.4 数据的读取与写入 12.5 文件内容的位置标记 12.6 将文件的存取写成函数 12.7 常犯的错误 12.8 本章重点 12.9 本章练习 第13章 输出格式 13.1 使用格式操作符设置输出格式 13.2 输出格式设置间的交互作用 13.3 3 种格式设置语法的比较 13.4 文件存储格式的设置 13.5 矩阵和向量间的操作 13.6 常犯的错误 13.7 本章重点 13.8 本章练习 第14章 程序计时 14.1 程序的基本计时方法 14.2 更精确的程序计时方法 14.3 常犯的错误 14.4 本章重点 14.5 本章练习 第15章 struct与数据结构 15.1 struct的声明和使用 15.2 struct构成的数组 15.3 struct数据类型与函数参数的传递 l5.4 struct实例的动态声明 15.5 指针成员与数据结构 15.6 union数据类型 15.7 enum数据类型 15.8 常犯的错误 15.9 本章重点 15.10 本章练习 第16章 命名空间 16.1 因为名称相同而造成的问题 16.2 命名空间的基本语法 16.3 命名空间成员的存取 16.4 使用“using指令”和“using声明”以存取命名空间的成员 16.5 标准命名空间 16.6 未命名的命名空间 16.7 常犯的错误 16.8 本章重点 16.9 本章练习 第17章 异常处理 17.1 异常及其特性 17.2 异常处理的基本语法 17.3 异常的处理过程 17.4 抛出enum实例作为异常对象 17.5 抛出类所定义的对象 17.6 常犯的错误 17.7 本章重点 17.8 本章练习 PARTⅢ 面向对象程序设计 第18章 类与对象 18.1 程序设计方法的演进 18.2 抽象化和数据的隐藏 18.3 对象与类的关系 18.4 以对象为基础的银行账户操作程序范例 18.5 以对象为基础的电梯操作仿真范例 18.6 友元函数 18.7 常犯的错误 18.8 本章重点 18.9 本章练习 第19章 组合与继承 19.1 既有类的再利用 19.2 组合(Composition) 19.3 组合对象的构造函数和析构函数 19.4 继承(Inheritance) 19.5 protected成员 19.6 派生类所定义的对象的构造和析构次序 19.7 混合组合和继承以建立新的类 19.8 常犯的错误 19.9 本章重点 19.10 本章练习 第20章 多态与虚拟函数 20.1 多态的基本概念 20.2 后期连接与虚拟函数 20.3 VPTR和VTABLE 20.4 纯虚拟函数与抽象类 20.5 重载虚拟函数 20.6 虚拟析构函数 20.7 常犯的错误 20.8 本章重点 20.9 本章练习 第21章 运算符重载 21.1 运算符使用的基本概念 21.2 补充几个类使用上的要点 21.3 使用成员函数重载二元运算符 21.4 使用friend函数重载二元运算符 21.5 重载一元运算符 21.6 含有指针数据成员的类 21.7 等效阻抗的计算 21.8 常犯的错误 21.9 本章重点 21.10 本章练习 第22章 面向对象的字符串处理 22.1 C风格的字符串和面向对象的string类 22.2 String对象的定义 22.3 字符串的更改、清除、剪接与部分复制 22.4 字符串之间的查找和比较 22.5 字符串对象与C.style孚符串的互换 22.6 常犯的错误 22.7 本章重点 22.8 本章练习 第23章 模板类向量和矩阵的定义 23.1 向量 23.2 Vector模板类 23.3 矩阵 23.4 Matrix模板类 23.5 对象数组的动态创造和删除 23.6 常犯的错误 23.7 本章重点 23.8 本章练习 第24章 泛型程序设计简介 24.1 C++标准模板连接库(STL) 24.2 STL的主要内容 24.3 使用STL的vector·容器类 24.4 使用STL处理字符串数组 24.5 使用complex容器类处理复数数据 24.6 常犯的错误 24.7 本章重点 24.8 本章练习 第25章 最优化问题的求解 25.1 最优化问题 25.2 Simplex最优化求解法 25.3 最优化演算的C++程序结构 25.4 没有约束条件的最优化问题实例 25.5 有约束条件的三维最优化问题 25.6 曲线拟合问题 25.7 常犯的错误 25.8 本章重点 25.9 本章练习 第26章 常微分方程式的数值解 26.1 常微分方程式 26.2 使用C++解初始值问题的程序结构 26.3 ODE初始值问题的数值解 26.4 程序计算结果的输出 26.5 van der Pol微分方程式的数值解 26.6 三阶ODE动态系统的数值仿真 26.7 常犯的错误 26.8 本章重点 26.9 本章练习 附录 附录A C++的74个关键字 附录B C++的运算符 附录C 标准链接库的常用头文件 附录D 函数的参数传递格式 附录E 重要名词中英对照表 附录F 重要参考网址 参考文献

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值