设计模式之模板方法模式C++实现
Posted 今天也要努力搬砖
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之模板方法模式C++实现相关的知识,希望对你有一定的参考价值。
需求场景
饮料店制作两种含咖啡因的饮料:茶和咖啡。茶和咖啡都包含以下4个步骤:
1、把水煮沸
2、冲泡
3、把饮料倒进杯子
4、加调料
这4个步骤的顺序是固定的,不希望被改变的。其中第1步和第3步对茶和咖啡来说都是同样的处理方式,可以放在基类中处理。第3步和第4步针对两种饮料处理方式不同,其中茶需要用沸水侵泡茶叶,加牛奶(对,就是制作奶茶,哈哈哈),咖啡需要用沸水冲泡咖啡,加糖,这种不同的处理方式需要在子类中实现。
基于上面的分析,可以得出以下类图结构
模式定义
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
类图如下
如上面需求场景中,在咖啡因饮料基类中,定义制作饮料的步骤(prepareRecipe方法中),子类茶和咖啡都不能改变这个步骤,但具体的冲泡方法brew和加调料方法addCondiments在子类中被重新定义。
代码实现
针对需求场景中的例子代码实现如下
// CaffeineBeverage.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
//Base Class CaffeineBeverage
class CaffeineBeverage
public:
virtual void prepareRecipe()final//用final修饰不希望子类覆盖该方法
boilWater();
brew();
pourInCup();
addCondiments();
virtual void brew() = 0;
virtual void addCondiments() = 0;
void boilWater()
std::cout << "Boiling water" << std::endl;
void pourInCup()
std::cout << "Pouring into cup" << std::endl;
;
//Concrete Class Tea
class Tea :public CaffeineBeverage
public:
virtual void brew()override
std::cout << "Steeping the tea" << std::endl;
virtual void addCondiments()override
std::cout << "Adding milk" << std::endl;
;
//Concrete Class Coffee
class Coffee :public CaffeineBeverage
public:
virtual void brew()override
std::cout << "Dripping COffe through filter" << std::endl;
virtual void addCondiments()override
std::cout << "Adding sugar" << std::endl;
;
int main()
Tea myTea;
Coffee myCoffee;
myTea.prepareRecipe();
std::cout << std::endl;
myCoffee.prepareRecipe();
运行测试效果如下
钩子函数
钩子是一种被声明在基类中的方法,但只有空的或者默认的实现。钩子的存在可以让子类有能力对算法的不同点进行挂钩,要不要挂钩,由子类自行决定。
以上面需求场景的例子举例钩子函数,我们加一个条件判断来决定是否要加调料,修改后代码如下
virtual void prepareRecipe()final//用final修饰不希望子类覆盖该方法
boilWater();
brew();
pourInCup();
if(customerWantsCondiments())
addCondiments();
其中 customerWantsCondiments()在基类中的默认实现返回true,子类可以覆盖这个方法,来具体决定是否需要加饮料,这个函数就是钩子函数。
virtual bool customerWantsCondiments()
return true;
在子类茶Tea中具体实现这个钩子函数,决定是否要加调料,代码如下
virtual bool Tea::customerWantsCondiments()override
char wants = ' ';
while (wants != 'Y' && wants != 'y'
&& wants != 'N' && wants != 'n')
std::cout << "Would you like milk with your tea?(Y/N)" << std::endl;
std::cin >> wants;
if (wants == 'y' || wants == 'Y')
return true;
else if (wants == 'n' || wants == 'N')
return false;
测试代码,运行效果如下
什么时候使用抽象方法,什么时候使用钩子?
当子类必须提供算法中的某个方法或步骤的实现时使用抽象方法(纯虚函数),如果算法的函数是可选的就用钩子(虚函数),如果这个步骤不想被改变使用final修饰的虚函数。
模板方法模式遵循 “别调用我,我会调用你”的设计原则,这防止了依赖腐败。当高层组件依赖底层组件,而底层组件又依赖高层组件,而高层组件又依赖边侧组件,而边侧组件又依赖底层组件时,依赖腐败就发生了。
以上是关于设计模式之模板方法模式C++实现的主要内容,如果未能解决你的问题,请参考以下文章