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

来源:互联网 发布:国内旅游 知乎 编辑:程序博客网 时间:2024/06/15 21:53

模板(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;}//钩子,子类覆盖这个钩子。在此默认返回truebool 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;}//钩子,子类覆盖这个钩子。在此默认返回truebool 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
原创粉丝点击