前言

模式介绍

在之前简单工厂模式中,我们介绍了简单工厂模式的缺陷是违背了开放-封闭原则。如果在面馆中添加了烤海参,那将会修改waiter工厂类。违背了类内封闭原则。

还以面馆为例,现在两种面,用一个服务员来卖就可以,如果这个服务员不干了,后面卖面的厨师需要兼职顶替服务员,但是厨师又不能离开灶台,就将模式改成了窗口排队式,一队海参炒面,另一队辣根汤面。每个窗口分别有一个厨师放饭,一个会做海参炒面,另一个会做辣根汤面。老板觉得这种模式挺好,万一来了一个会做烤海参的,就只需要开一个烤海参的窗口就好了,不需要重新要服务员学习,因为烤海参的就会卖。这就变成了工厂模式。

UML类图

这里涉及到2种类①我,客户端,排队买饭。②做饭厨师类,工厂类,为我生成饭。③菜品类,生成菜品类。具体关系如下UML类图:

代码实例

下面是noodle类,是为工厂类使用的,继承他就可以扩展noodle类别:

  1. #ifndef NOODLE_H
  2. #define NOODLE_H
  3. class noodle
  4. {
  5. public:
  6. noodle() {}
  7. ~noodle() {}
  8. virtual void eating() = 0;
  9. };
  10. #endif // NOODLE_H

下面是海参炒面类,继承了noodle,实现eating方法,吃海参炒面:

  1. #ifndef HAISHENNOODLE_H
  2. #define HAISHENNOODLE_H
  3. #include "noodle.h"
  4. class haishennoodle : public noodle
  5. {
  6. public:
  7. haishennoodle();
  8. ~haishennoodle();
  9. virtual void eating();
  10. };
  11. #endif // HAISHENNOODLE_H
  1. #include <iostream>
  2. #include "haishennoodle.h"
  3. haishennoodle::haishennoodle()
  4. {
  5. }
  6. haishennoodle::~haishennoodle()
  7. {
  8. }
  9. void haishennoodle::eating()
  10. {
  11. std::cout << "我是海参炒面,里面没有海参哦!!吃的时候注意!" << std::endl;
  12. }

下面是辣根汤面,继承了noodle,实现eating方法,吃辣根汤面:

  1. #ifndef LAGENNOODLE_H
  2. #define LAGENNOODLE_H
  3. #include "noodle.h"
  4. class lagennoodle : public noodle
  5. {
  6. public:
  7. lagennoodle();
  8. ~lagennoodle();
  9. virtual void eating();
  10. };
  11. #endif // LAGENNOODLE_H
  1. #include <iostream>
  2. #include "lagennoodle.h"
  3. lagennoodle::lagennoodle()
  4. {
  5. }
  6. lagennoodle::~lagennoodle()
  7. {
  8. }
  9. void lagennoodle::eating()
  10. {
  11. std::cout << "我是辣根汤面,吃完呛的哼啊!!!" << std::endl;
  12. }

下面是waiter工厂的基类。所有工厂都继承这个类:

  1. #ifndef WAITER_H
  2. #define WAITER_H
  3. class noodle;
  4. class waiter
  5. {
  6. public:
  7. waiter() {}
  8. ~waiter() {}
  9. virtual noodle *createnoodle() = 0;
  10. };
  11. #endif // WAITER_H

下面是海参厨师(工厂1),海参厨师只管做海参炒面,重写了createnoodle方法:

  1. #ifndef HAISHEN_H
  2. #define HAISHEN_H
  3. #include "waiter.h"
  4. class noodle;
  5. class haishen : public waiter
  6. {
  7. public:
  8. haishen();
  9. ~haishen();
  10. virtual noodle *createnoodle();
  11. };
  12. #endif // HAISHEN_H
  1. #include <iostream>
  2. #include "haishen.h"
  3. #include "haishennoodle.h"
  4. haishen::haishen()
  5. {
  6. }
  7. haishen::~haishen()
  8. {
  9. }
  10. noodle *haishen::createnoodle()
  11. {
  12. std::cout << "面是我炒得,我的名字叫海参!!!" << std::endl;
  13. return new haishennoodle();
  14. }

下面是辣根厨师(工厂1),辣根厨师只管做辣根汤面,重写了createnoodle方法:

  1. #ifndef LAGEN_H
  2. #define LAGEN_H
  3. #include "waiter.h"
  4. class lagen : public waiter
  5. {
  6. public:
  7. lagen();
  8. ~lagen();
  9. virtual noodle *createnoodle();
  10. };
  11. #endif // LAGEN_H
  1. #include <iostream>
  2. #include "lagen.h"
  3. #include "lagennoodle.h"
  4. lagen::lagen()
  5. {
  6. }
  7. lagen::~lagen()
  8. {
  9. }
  10. noodle *lagen::createnoodle()
  11. {
  12. std::cout << "吃辣根汤面,你不觉得呛得哼吗??" << std::endl;
  13. return new lagennoodle();
  14. }

下面是客户端,客户端通过类别,使用相应的工厂类建立相应的实例:

  1. #include <iostream>
  2. #include <string.h>
  3. #include "haishen.h"
  4. #include "lagen.h"
  5. #include "noodle.h"
  6. using namespace std;
  7. char *product_list[] = {
  8. "haishen-noodle",
  9. "lagen-noodle",
  10. NULL
  11. };
  12. int main()
  13. {
  14. char *p = NULL;
  15. char *pd = "haishen-noodle";
  16. int i = 0;
  17. waiter *w = NULL;
  18. noodle *n = NULL;
  19. for(p = product_list[i]; p != NULL; i++, p = product_list[i]) {
  20. if(strncmp(pd, p, strlen(pd)) == 0) {
  21. if(i == 0) {
  22. w = new haishen();
  23. } else if(i == 1) {
  24. w = new lagen();
  25. } else {
  26. cout << "对不起,请您排在队内!!!" << std::endl;
  27. break;
  28. }
  29. }
  30. }
  31. if(w) n = w->createnoodle();
  32. if(n) n->eating();
  33. if(w) {
  34. delete w; w = NULL;
  35. }
  36. if(n) {
  37. delete n; n = NULL;
  38. }
  39. return 0;
  40. }

下面是CMakeList.txt文件,帮助生成Makefile:

  1. cmake_minimum_required(VERSION 2.8)
  2. project(noodle-factory)
  3. set(SRC_LIST main.cpp noodle.h waiter.h haishen.h haishen.cpp haishennoodle.h haishennoodle.cpp
  4. lagennoodle.h lagennoodle.cpp lagen.h lagen.cpp)
  5. add_executable(${PROJECT_NAME} ${SRC_LIST})

编译运行结果

代码下载链接是:https://github.com/erguangqiang/freesir_headfirst/blob/master/noodle-factory.tar.gz

使用cmake生成Makefile,并编译出可执行程序noodle。运行结果如下:

  1. erguangqiang@elab$./noodle-factory
  2. 面是我炒得,我的名字叫海参!!!
  3. 我是海参炒面,里面没有海参哦!!吃的时候注意!

结束

工厂模式解决了简单工厂违背了的开放-封闭原则。虽然累的结构变的复杂了,但是对于扩展性得到了很大的提高。

深入浅出《设计模式》之工厂模式(C++)的更多相关文章

  1. 深入浅出设计模式——简单工厂模式(Simple Factory)

    介绍简单工厂模式不能说是一个设计模式,说它是一种编程习惯可能更恰当些.因为它至少不是Gof23种设计模式之一.但它在实际的编程中经常被用到,而且思想也非常简单,可以说是工厂方法模式的一个引导,所以我想 ...

  2. 深入浅出设计模式——抽象工厂模式(Abstract Factory)

    模式动机在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,一般情况下,一个具体工厂中只有一个工厂方法或者一组重载的工厂方法.但是有时候我们需要一个工厂可 ...

  3. 设计模式——抽象工厂模式及java实现

    设计模式--抽象工厂模式及java实现 设计模式在大型软件工程中很重要,软件工程中采用了优秀的设计模式有利于代码维护,方便日后更改和添加功能. 设计模式有很多,而且也随着时间在不断增多,其中最著名的是 ...

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

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

  5. 3. 星际争霸之php设计模式--简单工厂模式

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

  6. iOS 设计模式之工厂模式

    iOS 设计模式之工厂模式 分类: 设计模式2014-02-10 18:05 11020人阅读 评论(2) 收藏 举报 ios设计模式 工厂模式我的理解是:他就是为了创建对象的 创建对象的时候,我们一 ...

  7. 设计模式之工厂模式(Factory)

    设计模式的工厂模式一共有三种:简单工厂模式,工厂模式,抽象工厂模式 简单工厂模式原理:只有一个工厂类,通过传参的形式确定所创建的产品对象种类 代码如下: #include <stdio.h> ...

  8. php设计模式:工厂模式

    php设计模式:工厂模式 意图: 定义一个用于创建对象的接口,让子类决定实例化哪一个类. 工厂模式实现: 工厂模式中任何创建对象的工厂类都要实现这个接口,实现接口的方法体中都要实现接口中的方法,它声明 ...

  9. 浅析JAVA设计模式之工厂模式(一)

    1 工厂模式简单介绍 工厂模式的定义:简单地说,用来实例化对象,取代new操作. 工厂模式专门负责将大量有共同接口的类实例化.工作模式能够动态决定将哪一个类实例化.不用先知道每次要实例化哪一个类. 工 ...

  10. java 设计模式之工厂模式与反射的结合

    工厂模式: /**  * @author Rollen-Holt 设计模式之 工厂模式  */   interface fruit{     public abstract void eat(); } ...

随机推荐

  1. CSS 2D 转换

    通过CSS 2D转换,我们能够对元素进行移动.缩放.转动.拉长或拉伸. 2D转换一共五个属性:transfrom=> translate(X轴数值px,Y轴数值px):元素从其当前位置移动,根据 ...

  2. 利用Fiddler模拟通过Dynamics 365的OAuth 2 Client Credentials认证后调用Web API

    微软动态CRM专家罗勇 ,回复337或者20190521可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me. 配置Dynamics 365 & PowerApps 支 ...

  3. ABP进阶教程11 - 小结

    点这里进入ABP进阶教程目录 效果预览 至此,ABP进阶教程的查询/分页/排序/导出/打印示例已完成,效果如下 登录 首页 办公室信息 院系信息 课程信息 教职员信息 学生信息 新增 修改 删除 查询 ...

  4. 将vue2.9.6升级到vue3.0

    vue2.9.6没有ui界面可以用,直接使用yarn global add @cli没用,还是2.9.6版本 借鉴博客: https://juejin.im/post/5bf7d67c51882518 ...

  5. React Hooks究竟是什么呢?

    摘要: React Hooks原理解析. 原文:快速了解 React Hooks 原理 译者:前端小智 我们大部分 React 类组件可以保存状态,而函数组件不能? 并且类组件具有生命周期,而函数组件 ...

  6. 在PyCharm中打开文件的位置

    选中文件,右键选择  Show in Explorer (在资源管理器中显示) 只需要路径时,选择第四个Copy Path ,会复制文件的路径

  7. Linux使用Samba实现文件共享

    Samba服务是现在Linux系统与Windows系统之间共享文件的最佳选择. [root@study ~]# yum install samba -y #安装samba服务 [root@study ...

  8. vue+node+elementUI实现注册功能

    后端代码 在后端的文件 routes文件夹下的connect.js文件中 // 引入mysql const mysql = require('mysql'); // 创建连接对象 const conn ...

  9. django update_or_create

    update_or_create question.votes.update_or_create(user=request.user, defaults={"value": val ...

  10. Leetcode4__findMedianSortedArrays

    findMedianSortedArrays 基本思路:通过指针按顺序移动来判断大小顺序,思路和有一道用链表求中间值一样: class Solution { public double findMed ...