Head First设计模式C++实现--第八章:模板(Template)模式

模板(Template)模式

一、问题的提出

茶和咖啡的冲泡方式非常相似:
//咖啡冲泡法
prepareRecipe()
{
	boilWater();//1、把水煮沸
	brewCoffeeGrinds();//2、用沸水冲泡咖啡
	pourInCup();//3、把咖啡倒进杯子
	addSuarAndMilk();//4、加糖和牛奶
}

//茶冲泡法
prepareRecipe()
{
	boilWater();//1、把水煮沸
	steepTeaBag();//2、用沸水浸泡茶叶
	pourInCup();//3、把茶倒进杯子
	addLemon();//4、加柠檬
}
很明显上面有重复的代码,需要清理一下设计了。把相似的部分抽取出来,放进一个基类中。
以上的设计中把相同的两个方法抽出来放进了基类当中,但是第二、四步是一样的算法,只是应用在不同的饮料上。于是,可以抽象的将他们换一个更合适的方法,最终的设计便是:
prepareRecipe()
{
	boilWater();//1、把水煮沸
	brew();//2、用沸水冲泡
	pourInCup();//3、把饮料倒进杯子
	addCondiments();//4、加调料
}

二、认识模板方法

头文件:
#ifndef TEMPLATE__H
#define TEMPLATE__H
#include <iostream>
using namespace std;

//咖啡因饮料超类
class CaffeineBeverage
{
public:
	virtual void prepareRecipe() = 0;//这是模板方法,因为:它是一个算法的模板。(在这个例子中,这个算法是用来制作饮料的)

	//在这个模板中,算法内的每一个步骤都被一个方法代表了,某些方法是由这个超类处理的,某些方法由子类处理,需要子类处理的方法被声明为抽象
	void boilWater();
	virtual void brew() = 0;
	void pourInCup();
	virtual void addCondiments() = 0;
};

//茶
class Tea : public CaffeineBeverage
{
public:
	void brew();
	void addCondiments();
};

//咖啡
class Coffee : public CaffeineBeverage
{
public:
	void brew();
	void addCondiments();
};


#endif

cpp文件
#include "Template.h"
void CaffeineBeverage::boilWater()
{
	cout<<"Boiling water"<<endl;
}

void CaffeineBeverage::pourInCup()
{
	cout<<"Pouring into cup"<<endl;
}
//模板方法
void CaffeineBeverage::prepareRecipe()
{
	boilWater();
	brew();
	pourInCup();
	addCondiments();
}


void Tea::brew()
{
	cout<<"Steeping the tea"<<endl;
}

void Tea::addCondiments()
{
	cout<<"Adding Lemon"<<endl;
}

void Coffee::brew()
{
	cout<<"Dripping Coffee through filter"<<endl;
}

void Coffee::addCondiments()
{
	cout<<"Adding Sugar and Milk"<<endl;
}

定义模板方法模式:模板方法模式在一个方法中定义一个算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中某些实现步骤
这个模式就是用来创建一个算法的模板。什么是模板?模板就是一个方法。更具体的说,这个方法将算法定义成一组步骤,其中的任何步骤都可以是抽象的,有子类负责。这可以确保算法的结构保持不变,同时由子类提供部分实现。

2.1添加钩子

头文件:
//咖啡因饮料超类,具有钩子
class CaffeineBeverageWithHook
{
public:
	virtual void prepareRecipe() = 0;//这是模板方法,因为:它是一个算法的模板。(在这个例子中,这个算法是用来制作饮料的)

	//在这个模板中,算法内的每一个步骤都被一个方法代表了,某些方法是由这个超类处理的,某些方法由子类处理,需要子类处理的方法被声明为抽象
	void boilWater();
	virtual void brew() = 0;
	void pourInCup();
	virtual void addCondiments() = 0;

	//添加钩子函数,由顾客决定是否需要添加调料
	bool customerWantsCondiments();
};

class TeaWithHook : public CaffeineBeverageWithHook
{
public:
	void prepareRecipe();

	void brew();
	void addCondiments();
	bool customerWantsCondiments();
};

//咖啡
class CoffeeWithHook : public CaffeineBeverageWithHook
{
public:
	void prepareRecipe();

	void brew();
	void addCondiments();
	bool customerWantsCondiments();
};

cpp文件
void CaffeineBeverageWithHook::boilWater()
{
	cout<<"Boiling water"<<endl;
}

void CaffeineBeverageWithHook::pourInCup()
{
	cout<<"Pouring into cup"<<endl;
}

bool CaffeineBeverageWithHook::customerWantsCondiments()
{
	return true;
}

//模板方法
void CaffeineBeverageWithHook::prepareRecipe()
{
	boilWater();
	brew();
	pourInCup();
	if(customerWantsCondiments())
		addCondiments();
}

void TeaWithHook::brew()
{
	cout<<"Steeping the tea"<<endl;
}

void TeaWithHook::addCondiments()
{
	cout<<"Adding Lemon"<<endl;
}
//钩子,子类覆盖这个钩子。在此默认返回true
bool TeaWithHook::customerWantsCondiments()
{
	char t;
	cout<<"Would you like Lemon with your tea?(y/n)"<<endl;
	cin>>t;
	if(t == 'y')
		return true;
	return false;
}

void TeaWithHook::prepareRecipe()
{
	boilWater();
	brew();
	pourInCup();
	if(customerWantsCondiments())
		addCondiments();
}

void CoffeeWithHook::brew()
{
	cout<<"Dripping Coffee through filter"<<endl;
}

void CoffeeWithHook::addCondiments()
{
	cout<<"Adding Sugar and Milk"<<endl;
}
//钩子,子类覆盖这个钩子。在此默认返回true
bool CoffeeWithHook::customerWantsCondiments()
{
	char t;
	cout<<"Would you like milk and sugar with your coffee?(y/n)"<<endl;
	cin>>t;
	if(t == 'y')
		return true;
	return false;
}

void CoffeeWithHook::prepareRecipe()
{
	boilWater();
	brew();
	pourInCup();
	if(customerWantsCondiments())
		addCondiments();
}

测试代码:
#include "Template.h"
#include <iostream>
using namespace std;

int main()
{
	TeaWithHook* teaHook = new TeaWithHook();
	CoffeeWithHook* coffeeHook = new CoffeeWithHook();

	cout<<"Making tea..."<<endl;
	teaHook->prepareRecipe();

	cout<<endl<<"Making coffee..."<<endl;
	coffeeHook->prepareRecipe();

	delete teaHook;
	delete coffeeHook;

	getchar();
	getchar();
}

好莱坞原则:别调用我们,我们会调用你。
当我们设计模板方法模式时,我们告诉子类,“不要调用我们,我们会调用你”。

三、模板和策略模式的比较

模板方法模式:
1、定义一个算法大纲,由其子类定义其中某些步骤的内容。这么一来,在算法中的个别步骤可以有不同的实现细节,但是算法的结构依然维持不变。
2、对算法由更多的控制权,而且不会重复代码。事实上,除了极少的一部分之外,算法的每一个部分都是相同的,所以类的效率高一些。会重复使用到的代码,都被放进了超类当中,好让所有子类继承。
策略模式:
1、定义一个算法家族,并让这些算法可以互换。正因为每一个散发都被封装起来了,所以客户可以轻易地使用不同的算法。
2、使用对象组合,比较有弹性,客户能在运行时改变算法,而客户所要做的,只是改用不同的策略对象。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值