介绍

前文初始篇C++ 深入浅出工厂模式(初始篇),主要阐述了简单工厂模式、工厂方法模式和抽象工厂模式的结构、特点和缺陷等。以上三种方式,在新增产品时,要么修改工厂类,要么需新增具体的工厂类,说明工厂类的封装性还不够好。

本文进阶篇,主要是将工厂类的封装性提高,达到新增产品时,也不需要修改工厂类,不需要新增具体的工厂类。封装性高的工厂类特点是扩展性高、复用性也高。

模板工厂

针对工厂方法模式封装成模板工厂类,那么这样在新增产品时,是不需要新增具体的工厂类,减少了代码的编写量。

UML图:

模板工厂代码:
  • ShoesClothe,分别为鞋子和衣服的抽象类(基类)
  • NiKeShoesUniqloClothe,分别为耐克鞋子和优衣库衣服具体产品类。
// 基类 鞋子
class Shoes
{
public:virtual void Show()= 0;virtual ~Shoes() {}
};// 耐克鞋子
class NiKeShoes : public Shoes
{
public:void Show(){std::cout << "我是耐克球鞋,我的广告语:Just do it" << std::endl;}
};// 基类 衣服
class Clothe
{
public:virtual void Show()= 0;virtual ~Clothe() {}
};// 优衣库衣服
class UniqloClothe : public Clothe
{
public:void Show(){std::cout << "我是优衣库衣服,我的广告语:I am Uniqlo" << std::endl;}
};
  • AbstractFactory为抽象模板工厂类,其中模板参数:AbstractProduct_t 产品抽象类,如ShoesClothe
  • ConcreteFactory为具体模板工厂类,其中模板参数:AbstractProduct_t 产品抽象类(如ShoesClothe),ConcreteProduct_t 产品具体类(如NiKeShoesUniqloClothe
// 抽象模板工厂类
// 模板参数:AbstractProduct_t 产品抽象类
template <class AbstractProduct_t>
class AbstractFactory
{
public:virtual AbstractProduct_t *CreateProduct()= 0;virtual ~AbstractFactory() {}
};// 具体模板工厂类
// 模板参数:AbstractProduct_t 产品抽象类,ConcreteProduct_t 产品具体类
template <class AbstractProduct_t, class ConcreteProduct_t>
class ConcreteFactory : public AbstractFactory<AbstractProduct_t>
{
public:AbstractProduct_t *CreateProduct(){return new ConcreteProduct_t();}
};
  • main函数,根据不同类型的产品,构造对应的产品的工厂对象,便可通过对应产品的工厂对象创建具体的产品对象。
int main(){// 构造耐克鞋的工厂对象ConcreteFactory<Shoes, NiKeShoes> nikeFactory;// 创建耐克鞋对象Shoes *pNiKeShoes = nikeFactory.CreateProduct();// 打印耐克鞋广告语pNiKeShoes->Show();// 构造优衣库衣服的工厂对象ConcreteFactory<Clothe, UniqloClothe> uniqloFactory;// 创建优衣库衣服对象Clothe *pUniqloClothe = uniqloFactory.CreateProduct();// 打印优衣库广告语pUniqloClothe->Show();// 释放资源delete pNiKeShoes;pNiKeShoes = NULL;delete pUniqloClothe;pUniqloClothe = NULL;return 0;
}
  • 输出结果:
[root@lincoding factory]# ./templateFactory
我是耐克球鞋,我的广告语:Just do it
我是优衣库衣服,我的广告语:I am Uniqlo

产品注册模板类+单例工厂模板类

前面的模板工厂虽然在新增产品的时候,不需要新增具体的工厂类,但是缺少一个可以统一随时随地获取指定的产品对象的类。

还有改进的空间,我们可以把产品注册的对象用std::map的方式保存,通过key-valve的方式可以轻松简单的获取对应的产品对象实例。

实现大致思路:

  • 把产品注册的功能封装成产品注册模板类。注册的产品对象保存在工厂模板类的std::map,便于产品对象的获取。

  • 把获取产品对象的功能封装成工厂模板类。为了能随时随地获取指定产品对象,则把工厂设计成单例模式。

UML图:

产品注册模板类+单例工厂模板类:
  • IProductRegistrar为产品注册抽象类,模板参数 ProductType_t 表示的类是产品抽象类(如ShoesClothe)。提供了产品对象创建的纯虚函数CreateProduct
  • ProductFactory为工厂模板类,模板参数 ProductType_t 表示的类是产品抽象类(如ShoesClothe)。用于保存注册产品对象到std::map中和获取对应的产品对象。
  • ProductRegistrar为产品注册模板类,模板参数 ProductType_t 表示的类是产品抽象类(如ShoesClothe),ProductImpl_t 表示的类是具体产品(如NikeShoesUniqloClothe)。用于注册产品到工厂类和创建产品实例对象。
// 基类,产品注册模板接口类
// 模板参数 ProductType_t 表示的类是产品抽象类
template <class ProductType_t>
class IProductRegistrar
{
public:// 获取产品对象抽象接口virtual ProductType_t *CreateProduct()= 0;protected:// 禁止外部构造和虚构, 子类的"内部"的其他函数可以调用IProductRegistrar() {}virtual ~IProductRegistrar() {}private:// 禁止外部拷贝和赋值操作IProductRegistrar(const IProductRegistrar &);const IProductRegistrar &operator=(const IProductRegistrar &);
};// 工厂模板类,用于获取和注册产品对象
// 模板参数 ProductType_t 表示的类是产品抽象类
template <class ProductType_t>
class ProductFactory
{
public:// 获取工厂单例,工厂的实例是唯一的static ProductFactory<ProductType_t> &Instance(){static ProductFactory<ProductType_t> instance;return instance;}// 产品注册void RegisterProduct(IProductRegistrar<ProductType_t> *registrar, std::string name){m_ProductRegistry[name] = registrar;}// 根据名字name,获取对应具体的产品对象ProductType_t *GetProduct(std::string name){// 从map找到已经注册过的产品,并返回产品对象if (m_ProductRegistry.find(name) != m_ProductRegistry.end()){return m_ProductRegistry[name]->CreateProduct();}// 未注册的产品,则报错未找到std::cout << "No product found for " << name << std::endl;return NULL;}private:// 禁止外部构造和虚构ProductFactory() {}~ProductFactory() {}// 禁止外部拷贝和赋值操作ProductFactory(const ProductFactory &);const ProductFactory &operator=(const ProductFactory &);// 保存注册过的产品,key:产品名字 , value:产品类型std::map<std::string, IProductRegistrar<ProductType_t> *> m_ProductRegistry;
};// 产品注册模板类,用于创建具体产品和从工厂里注册产品
// 模板参数 ProductType_t 表示的类是产品抽象类(基类),ProductImpl_t 表示的类是具体产品(产品种类的子类)
template <class ProductType_t, class ProductImpl_t>
class ProductRegistrar : public IProductRegistrar<ProductType_t>
{
public:// 构造函数,用于注册产品到工厂,只能显示调用explicit ProductRegistrar(std::string name){// 通过工厂单例把产品注册到工厂ProductFactory<ProductType_t>::Instance().RegisterProduct(this, name);}// 创建具体产品对象指针ProductType_t *CreateProduct(){return new ProductImpl_t();}
};
  • main函数,通过ProductRegistrar注册各种不同类型产品,在统一由ProductFactory单例工厂获取指定的产品对象。
int main(){// ========================== 生产耐克球鞋过程 ===========================//// 注册产品种类为Shoes(基类),产品为NiKe(子类)到工厂,产品名为nikeProductRegistrar<Shoes, NiKeShoes> nikeShoes("nike");// 从工厂获取产品种类为Shoes,名称为nike的产品对象Shoes *pNiKeShoes = ProductFactory<Shoes>::Instance().GetProduct("nike");// 显示产品的广告语pNiKeShoes->Show();// 释放资源if (pNiKeShoes){delete pNiKeShoes;}// ========================== 生产优衣库衣服过程 ===========================//// 注册产品种类为Clothe(基类),产品为UniqloClothe(子类)到工厂,产品名为uniqloProductRegistrar<Clothe, UniqloClothe> adidasShoes("uniqlo");// 从工厂获取产品种类为Shoes,名称为adidas的产品对象Clothe *pUniqloClothe = ProductFactory<Clothe>::Instance().GetProduct("uniqlo");// 显示产品的广告语pUniqloClothe->Show();// 释放资源if (pUniqloClothe){delete pUniqloClothe;}return 0;
}
  • 输出结果:
[root@lincoding factory]# ./singleFactory
我是耐克球鞋,我的广告语:Just do it
我是优衣库衣服,我的广告语:I am Uniqlo

总结

将工厂方法模式改良成模板工厂,虽然可以解决产品新增时,不需要新增具体工厂类,但是缺少一个可以随时随地获取产品对象的方式,说明还有改进的空间。

将模板工厂改良成产品注册模板类+单例工厂模板类,产品注册模板类用于注册不同类型的产品,单例工厂模板类用于获取指定已注册的产品对象。这种方式,可以把工厂模式中产品的注册和获取的主要功能很好的抽象成两个类,并且使用单例模式使得工厂类可以随时随地获取已注册的产品对象。

所以产品注册模板类+单例工厂模板类的工厂模式,达到了开闭法则,并且扩展性高和封装度高。

PS:想学习更多单例模式,可以参考C++ 线程安全的单例模式总结文章阅读。

标签: Linux, C/C++
好文要顶 关注我 收藏该文

小林coding
关注 - 0
粉丝 - 1

+加关注

0
0

« 上一篇: C++ 深入浅出工厂模式(初识篇)

posted @ 2019-09-15 21:38 小林coding 阅读(17) 评论(0) 编辑 收藏

刷新评论刷新页面返回顶部
发表评论

昵称:

评论内容:

不改了 退出 订阅评论

[Ctrl+Enter快捷键提交]

【推荐】超50万C++/C#源码: 大型实时仿真组态图形源码
【推荐】零基础轻松玩转华为云产品,获壕礼加返百元大礼
【推荐】天翼云开学季,学生必备云套餐,每月仅需9块9
【推荐】华为云文字识别资源包重磅上市,1元万次限时抢购
【福利】git pull && cherry-pick 博客园&华为云百万代金券
相关博文:
· 欢迎光临博客园
· 设计模式----工厂模式(c++)
· c++设计模式之工厂模式
· 深入浅出工厂模式
· Java进阶篇设计模式之二-----工厂模式
最新 IT 新闻:
· 微软Edge团队重新塑造三星Fold等折叠屏手机网页体验
· Linux Kernel 5.3正式发布:支持Intel Speed Select
· 生命化学分子如何起源于太空?碳分子形成环状化合物
· 外媒:苹果正在变成一家相机公司
· 星际旅行真的可能实现吗?
» 更多新闻...

转载于:https://www.cnblogs.com/ylaoda/p/11525696.html

C++ 深入浅出工厂模式(进阶篇)相关推荐

  1. java gof_java GOF23设计模式-简单工厂模式进阶

    不修改已有代码,而是添加代码 不和所有类打交道,只和总接口的实现类打交道 public class Cilent { public static void main(String[] args) { ...

  2. 设计模式--工厂类进阶

    1 工厂模式逻辑图 第一篇:工厂模式1 1.1 简单工厂模式 1.2 工厂模式 注:一个具体工厂只能生产一个产品: 1.3抽象工厂模式 注:一个具体工厂可以生产多个个产品: 2工厂模式改进 2.1 工 ...

  3. 设计模式-工厂模式 C++

    一.简介 工厂模式属于一种创建型模式,它提供一种创建对象的最佳方式,对外不暴露对象的创建,并且通过一个共同的接口获取对象指针. 就像一个工厂根据消费者的需求生产不同的产品,但是并不需要对消费者开放生产 ...

  4. python抽象工厂模式_Python设计模式之抽象工厂模式

    Python设计模式之抽象工厂模式 这篇文章主要为大家详细介绍了Python设计模式之抽象工厂模式,感兴趣的小伙伴们可以参考一下 python面向对象编程入门,我们需要不断学习进步 "&qu ...

  5. 设计模式之不简单的工厂模式(一)

    谈起设计模式中两个最简单的设计模式第一个大家想到的应该就是单例模式,第二个想必就是工厂模式了,拿我自身而言之前一直以来对工厂方法认识较浅,只觉得所谓的工厂模式就是将创建对象的过程封装到一个工厂类里面, ...

  6. 一口气讲完设计模式(单例模式、工厂模式、原型模式、建造者模式、适配器、桥梁模式)

    设计模式 使用设计模式,可以让我们的代码具有更好的可读性.可扩展性.可读性.重用性.符合高内聚低耦合的特点.作为程序员,是我们经常听到的概念,也是我们程序员必须深入学习,了解的知识. 设计模式种类 该 ...

  7. 虚无空间java下载_Java进阶篇设计模式之二 ----- 工厂模式

    前言 在上一篇中我们学习了单例模式,介绍了单例模式创建的几种方法以及最优的方法.本篇则介绍设计模式中的工厂模式,主要分为简单工厂模式.工厂方法和抽象工厂模式. 简单工厂模式 简单工厂模式是属于创建型模 ...

  8. java设计模式中不属于创建型模式_23种设计模式第二篇:java工厂模式定义:工厂模式是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式...

    23种设计模式第二篇:java工厂模式 定义: 工厂模式是 Java 中最常用的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 工厂模式主要是为创建对象提供过渡接口, ...

  9. 《深入浅出设计模式-中文版》读书笔记-工厂模式(五)

    今天给大家带来的是:工厂模式. 我们在代码中创建一个对象,我们会很自然的想到new.其实,除了new意外,我们还有很多的方式可以创建对象.不说复杂的模式,就说简单的语法,其实.NET框架中还有下面的方 ...

最新文章

  1. BZOJ3473:字符串(后缀数组,主席树,二分,ST表)
  2. css3-巧用选择器 “:target”
  3. 查找数组中第二个最小元素
  4. 用神经网络模拟分子:钾的卤化物
  5. @产品部 -- 腾讯策划部是如何培养用户的《王者荣耀》“瘾”的
  6. 快手直播平台演进之路
  7. Error -Cannot add direct child without default aggregation defined for control
  8. LA 3523 圆桌骑士
  9. 免签约微信支付宝个人收款接口pxpay v2.0.4
  10. 【今日CV 计算机视觉论文速览】Tue, 26 Feb 2019
  11. 还在纠结数据仓库和数据湖的二选一?滴普科技FastData教你两手兼得
  12. java reduce 分组_使用JAVA8 stream中三个参数的reduce方法对List进行分组统计
  13. jmeter 聚合报告说明_Jmeter 测试结果分析之聚合报告简介
  14. “我爱淘”冲刺阶段Scrum站立会议3
  15. Omnipeek 抓包工具
  16. linux虚拟机简单部署以及安装可视化界面
  17. 最新抖音下载无水印视频
  18. 2022年8月Python小屋编程比赛获奖名单(送5本书)
  19. my.cnf文件详解
  20. 看名言后的心得体会学会融会贯通

热门文章

  1. 软件之母—格蕾丝·霍波
  2. Linux 太难了?你需要知道这 5 点
  3. 51单片机-DS18B20单片
  4. DragGAN:interactive point-based manipulation on the generative image manifold
  5. 计算机考研材料哥,【材料哥分享-10期】材料哥:我对考研期间谈恋爱的看法
  6. 做一个理想现实主义者而不是幻想世俗主义者
  7. 制定销售和现金流量计划
  8. [图形学] 《Real-Time Rendering》碰撞检测(三)
  9. 2020年广东工业大学第十届文远知行杯新生程序设计竞赛 A.肥猪的钢琴床(dp动态规划)
  10. NOIP2017初赛 格子连动问题