学以致用C++设计模式 之 “工厂模式”
老板来杯奶茶
一个好朋友开了家奶茶店,生意很是红火。 今天我带着几个朋友去给他捧场,到了店里,老板给出了菜单:
香草味珍珠奶茶加椰果 草莓味双皮奶加珍珠 拿铁 巧克力瑞纳冰
A说:老板,草莓味双皮奶加珍珠。B说:老板,香草味珍珠奶茶加椰果。C说:拿铁一杯谢谢。我说:巧克力瑞纳冰,外加免费谢谢。
老板听得一脸黑线,但还是去了。我呢,看他那么赚钱,也想学两手,也就跟着去了。 只见老板把一众拆料摆在桌子上,一会儿加这个材料,一会儿加那个材料,然后放机器上加工一下,打包解决。
该过程涉及三个不同对象:老板、加工机器、不同种类的奶茶。
老板可以用场景类Client表示,加工机器类似于一个工厂,负责制作产品,不同种类的奶茶,它们都是同一个接口下的不同具体实现类,都是奶茶嘛,只是成分不同,口味不同而已。
分析完毕,那么我们就可以把类图画出来:
小故事代码实现
#include<iostream>
using namespace std;
//奶茶主类
class Milk {
public:
virtual void set_taste() = 0;//设置口味
virtual void add_burdening() = 0;//加料
};
//双皮奶
class custard :public Milk {
public:
void set_taste() { cout << "草莓味双皮奶" << endl; }
void add_burdening() { cout << "加珍珠" << endl; }
};
//珍珠奶茶
class pearl :public Milk {
public:
void set_taste() { cout << "香草味珍珠奶茶" << endl; }
void add_burdening() { cout << "加椰果" << endl; }
};
//拿铁
class coffee :public Milk {
public:
void set_taste() { cout << "拿铁" << endl; }
void add_burdening() { cout << "不加料" << endl; }
};
//巧克力瑞纳冰
class ruinaice :public Milk {
public:
void set_taste() { cout << "巧克力瑞纳冰" << endl; }
void add_burdening() { cout << "加奶油" << endl; }
};
//所有饮品定义完毕,接下来定义一台机器
//template<class T>
class abstractMachin {
public:
virtual void createMilk(Milk *c) = 0;
};
//机器具体实现
//template<class T>
class Machin :public abstractMachin {
public:
void createMilk(Milk *c) {
c->set_taste();
c->add_burdening();
}
};
//现在材料有了,机器也有了,是时候做奶茶了
class Boss {
//老板就是那个main()
};
int main() {
//初始化一个机器
abstractMachin* am = new Machin();
//先做瑞纳冰
Milk* ruina = new ruinaice();
am->createMilk(ruina);
return 0;
}
感悟
写的时候,我也发现这种模式有点不太方便,可以发现上面类图有个纰漏,那个string的传参,我下意识的把这个模式和装饰者模式混一起去了。我觉得这个模式和“装饰者”、“建造者”模式有很多相同的地方,但是那两个模式明显要有优势,这个模式的优势就在于:它更简单。
上面那个抽象机器类其实应该用模板会比较通用,成为一个通用接口。
工厂方法的定义
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使得一个类的实例化延迟到其子类(后面你会发现好多设计模式都能,应该是因为这个设计模式出来的早吧,后面的设计模式都参考了它的思想)。
工厂方法模式的应用
优势
1、良好的封装性 2、拓展性优秀 3、屏蔽产品类 4、典型的解耦框架,高层模块只需要知道产品的抽象类,具体实现和它们没关系。
使用场景
需要灵活的、可拓展的框架时。
学以致用
请自己实现一个“俄罗斯方块产生”功能,自己设计。
工厂方法模式拓展
1、缩小为简单工厂模式 2、升级为多个工厂,比方说老板现在不仅卖奶茶,他还要卖香肠、卖果汁、卖汉堡。那他就需要烤汉堡机,烤香肠机、榨汁机、奶茶机,所以我说抽象机器类要用模板。如果觉得前面太简单,可以做一下这个。
今天先到这里,明天见(抽象工厂模式)。
- 洛谷 P1055 ISBN号码【字符串+模拟】
- 【Java学习笔记之十二】Java8增强的工具类:Arrays的用法整理总结
- 利用insert,update和delete注入获取数据
- 【机器学习笔记之二】决策树的python实现
- 【Java学习笔记之十三】初探Java面向对象的过程及代码实现
- 洛谷 P1308 统计单词数【字符串+模拟】
- 【Java学习笔记之十四】Java中this用法小节
- Codeforces 839E Mother of Dragons【__builtin_popcount()的使用】
- 【Java学习笔记之十五】Java中的static关键字解析
- Codeforces 839D Winter is here【数学:容斥原理】
- Codeforces 839C Journey【DFS】
- Facebook的漏洞可以让攻击者在分分钟内重置用户账户密码
- 【Java学习笔记之十七】Java中普通代码块,构造代码块,静态代码块区别及代码示例分析
- 【机器学习笔记之六】Bagging 简述
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- beego(一) beego 入门
- javascript预编译(执行期的上下文)
- Elasticsearch评分相关度算法解析
- Netty入门教程——认识Netty
- Linux下的包过滤软件:iptables剖析
- rxjs fromEvent的实现
- rxjs switchMap的实现原理
- rxjs里scan operator的执行研究
- rxjs pipe和map组合的一个实际例子的单步调试
- Win10+Python2.7.14+cocos2d-x-3.17.2+VS2017环境搭建
- VUE-001-在表格单元格(el-table-column)中添加超链接访问
- 关于vue的title标签中出现的htmlWebpackPlugin.options.title
- dotnet tool 工具安装提示 Could not find a part of the path 安装失败
- dotnet core 进行 XML 序列化抛出 XmlSerializers dll 文件找不到
- C# dotnet 高性能多线程工具 ExecuteOnceAwaiter 只执行一次的任务