设计模式均整理自李建忠老师的设计模式入门课
模板模式定义
定义一个操作中的算法的骨架 (稳定),而将一些步骤延迟(变化)到子类中。Template Method使得子类可以不改变(复用)一个算法的结构即可重定义(override 重写)该算法的某些特定步骤。
动机
- 在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现。
- 如何在确定稳定操作结构的前提下,来灵活应对各个子步骤的变化或者晚期实现需求?
模版模式的优缺点
优点
- 封装不变的部分,将不变的部分抽取出来;
- 扩展可变部分,将可变的设置抽象方法,让具体子类来实现。
- 抽取的公共代码,便于后期维护
- 行为有基类来控制,具体操作有子类实现。
缺点
- 每一个不同的实现都需要有一个子类来实现,这样就会导致类的数量大大的增加,使得系统更加庞大。
模版模式的使用场景
在软件设计中,有些功能很类似,只是在某些环节不同而已。大多数环节都是相同的时候,可以使用模板模式。将通用的算法或者步骤抽取到抽象类中,在具体子类中实现具体特定的操作
模板模式的结构和实现
模式结构
模板方法模式由两部分结构组成
-
第一部分是抽象父类
-
第二部分是具体的实现子类。
通常在抽象父类中封装了子类的算法框架,包括实现一些公共方法以及封装子类中所有方法的执行顺序。子类通过继承这个抽象类,也继承了整个算法结构,并且可以选择重写父类的方法。
实现
此处在李老师的课程中使用下面例子讲述Template method
Templatelib.cpp
#include <iostream>
using namespace std;
//程序库开发人员
class Library
{
public:
//稳定 template method
void Run()
{
Step1();
if (Step2())
{ //支持变化 ==> 虚函数的多态调用
Step3();
}
for (int i = 0; i < 4; i++)
{
Step4(); //支持变化 ==> 虚函数的多态调用
}
Step5();
}
virtual ~Library() {}
protected:
void Step1()
{ //稳定
cout << "Step1" << endl;
}
void Step3()
{ //稳定
cout << "Step3" << endl;
}
void Step5()
{ //稳定
cout << "Step5" << endl;
}
virtual bool Step2() = 0; //变化
virtual void Step4() = 0; //变化
};
Template.cpp
#include "Templatelib.cpp"
#include <iostream>
using namespace std;
//应用程序开发人员
class Application : public Library
{
protected:
virtual bool Step2()
{
//... 子类重写实现
cout << "override Step2" << endl;
return true;
}
virtual void Step4()
{
//... 子类重写实现
cout << "override Step4" << endl;
}
};
int main()
{
Library *pLib = new Application();
pLib->Run();
delete pLib;
}
运行结果:
Step1
override Step2
Step3
override Step4
override Step4
override Step4
override Step4
Step5
分析:可以看出,通过使用模板方法,可以约束子类的行为,另子类按照父类的设定进行运行,避免子类实现的不规范,使得程序可以灵活的被调用。
实例
下面给出大话设计模式中的程序实例,通过Template pattern 实现煮茶的步骤:
CaffeineBeverage.hpp
#ifndef CAFFEINEBEVERAGE_HPP
#define CAFFEINEBEVERAGE_HPP
#include <iostream>
class CaffeineBeverage {
public:
virtual ~CaffeineBeverage(){}
void prepareRecipe() {
boilWater();
brew();
pourInCup();
if(customerWantsCondiments())
addCondiments();
}
virtual void brew() = 0;
virtual void addCondiments() = 0;
void boilWater() {
std::cout << "Boiling water\n";
}
void pourInCup() {
std::cout << "Pouring into cup\n";
}
virtual bool customerWantsCondiments() {
return true;
}
};
#endif
Coffee.cpp
#ifndef COFFEE_HPP
#define COFFEE_HPP
#include "CaffeineBeverage.hpp"
#include <iostream>
class Coffee : public CaffeineBeverage {
public:
~Coffee(){}
void brew() {
std::cout << "Dripping Coffee through filter\n";
}
void addCondiments() {
std::cout << "Adding Sugar and Milk\n";
}
bool customerWantsCondiments() {
char c;
std::cout << "Do you want to add condiments?\n";
std::cin >> c;
if(c == 'y')
return true;
else
return false;
}
};
#endif
Tea.cpp
#ifndef TEA_HPP
#define TEA_HPP
#include "CaffeineBeverage.hpp"
#include <iostream>
class Tea : public CaffeineBeverage {
public:
~Tea(){}
void brew() {
std::cout << "Steeping the tea\n";
}
void addCondiments() {
std::cout << "Adding Lemon\n";
}
bool customerWantsCondiments()
{
char c;
std::cout << "Do you want to add condiments?\n";
std::cin >> c;
if (c == 'y')
return true;
else
return false;
}
};
#endif
main.cpp
#include "Tea.hpp"
#include "Coffee.hpp"
int main() {
Tea* tea = new Tea();
Coffee* coffee = new Coffee();
std::cout << "\nMaking tea...\n";
tea->prepareRecipe();
std::cout << "\nMaking coffee...\n";
coffee->prepareRecipe();
delete tea;
delete coffee;
}
输出
Making tea...
Boiling water
Steeping the tea
Pouring into cup
Do you want to add condiments?
y
Adding Lemon
Making coffee...
Boiling water
Dripping Coffee through filter
Pouring into cup
Do you want to add condiments?
y
Adding Sugar and Milk
重点
- Template Method模式是一种非常基础性的设计模式,在面向对象系统中有着大量的应用。它用最简洁的机制(虚函数的多态性)为很多应用程序框架提供了灵活的扩展点,是代码复用方面的基本实现结构。
- 除了可以灵活应对子步骤的变化外,“不要调用我,让我来调用你”的反向控制结构Template Method的典型应用。
- 在具体实现方面,被Template Method调用的虚方法可以具有实现,也可以没有任何实现(抽象方法、纯虚方法),但一般推荐将它们设置为protected方法。
整理自:
https://blog.csdn.net/qq_40124555/article/details/126131599
https://github.com/Bigmartin121/C-plusplus-design-patterns-Li/tree/main/Template-Pattern