设计模式 - 模版方法
场景
小张的团队最近接受一个需求,实现实现一家咖啡店的冲泡咖啡和茶的冲泡自动化。之前这家咖啡店都是由咖啡师傅手动进行调制咖啡和茶。现在咖啡店需要引入自动化的点单和调制饮料的系统,小张负责实现调制饮料的功能。
咖啡师傅手工冲泡咖啡和茶的流程:
冲泡咖啡:
把水煮沸
用沸水冲泡咖啡
把咖啡倒入杯子
加糖和牛奶
冲泡茶:
把水煮沸
用沸水冲泡茶叶
把茶倒入杯子
加柠檬
小张先简单的想了一下, 如果直接实现程序,那么新建调制咖啡和调制茶的对象,在每个对象里面实现上述步骤。这样想了之后小张本想直接实现,但是由于信心不足,找老王帮他code review一下思路。 老王说,小张啊,你这实现也可以,不过不够优雅啊,你在仔细看一下上述步骤,有没有发现重复或者共性。
小张听了老王的话,觉得自己的设计应该太粗暴了,按照老王的引导,小张仔细看了上述步骤,发现上述步骤,1和4 是很相像的。4(加糖和牛奶/加柠檬)步骤相当于增加调料本质是相同的。那么他应该封装一下冲泡咖啡/茶的步骤算法。
找出共性进行封装,减少重复代码,使系统达到维护和扩展成本很低的状态。
老王夸奖到,很不错嘛,小张你已经慢慢的了解了面向对象(OOP)及使用设计模式的原因。你可以了解一下模版方法。
模版方法
模版方法实现冲泡咖啡
小张去了解了一下模版方法。针对上述冲泡步骤进行了思考。
应该有一个抽象的对象来描述冲泡饮料这一行为,并且抽象的类实现了具体冲泡对象的共性步骤也就是1.把水煮沸和3.把饮料倒入杯子。有两个具体的子类来具体实现冲泡茶和咖啡。
并且有些客户不需要加调料,那么需要对最后一步进行判断,是否添加调料。
我们来看一下小张的类图:
模版方法:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模版方法使得子类可以在不改变算法结构的情况下,重新定义算法中某些步骤
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
//抽象的制作饮料方法
class MakeDrink
{
public:
//1 把水煮开
void boil() {
cout << "把水煮开" << endl;
}
//2 冲某物
virtual void brew() = 0;
//3 从大杯倒入小杯
void putInCup()
{
cout << "把冲泡好的饮料 从大杯倒入小杯" << endl;
}
//4 加一些酌料
virtual void addThings() = 0;
//钩子函数, hook
virtual bool CustomWantAddThings() {
return true;
}
//业务的逻辑的统一模板
void make() {
boil();
brew(); //子类
putInCup();
if (CustomWantAddThings() == true) {
addThings(); //子类的多态
}
}
};
//制作咖啡
class MakeCoffee :public MakeDrink
{
public:
MakeCoffee(bool isAdd)
{
this->isAdd = isAdd;
}
//2 冲某物
virtual void brew()
{
cout << "冲泡咖啡豆" << endl;
}
//4 加一些酌料
virtual void addThings() {
cout << "添加糖和牛奶" << endl;
}
virtual bool CustomWantAddThings() {
return isAdd;
}
private:
bool isAdd;
};
//冲泡茶叶
class MakeTea :public MakeDrink
{
public:
MakeTea(bool isAdd)
{
this->isAdd = isAdd;
}
//2 冲某物
virtual void brew() {
cout << "冲泡 茶叶" << endl;
}
//4 加一些酌料
virtual void addThings() {
cout << "添加 柠檬 或者 菊花" << endl;
}
virtual bool CustomWantAddThings() {
return isAdd;
}
private:
bool isAdd;
};
int main(void)
{
MakeDrink *makeCoffee = new MakeCoffee(true);
makeCoffee->make();
cout << " ------ " << endl;
MakeDrink *makeTea = new MakeTea(false);
makeTea->make();
return 0;
}