用来对类或对象怎样交互和怎样分配职责进行描述。
定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
模板方法模式中的角色和职责
AbstractClass(抽象类):在抽象类中定义了一系列基本操作,这些基本操作可以是具体的,也可以是抽象的,每一个基本操作对应算法的一个步骤,在其子类中可以重定义或实现这些步骤。同时,在抽象类中实现了一个模板方法(Template Method),用于定义一个算法的框架,模板方法不仅可以调用在抽象类中实现的基本方法,也可以调用在抽象类的子类中实现的基本方法,还可以调用其他对象中的方法。
ConcreteClass(具体子类):它是抽象类的子类,用于实现在父类中声明的抽象基本操作以完成子类特定算法的步骤,也可以覆盖在父类中已经实现的具体基本操作。
模板方法模式的案例
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
//抽象模板
class DrinkTemplate
{
public:
virtual void BoilWater() = 0; //煮开水
virtual void Brew() = 0; //冲泡
virtual void PourInCup() = 0; //倒入杯中
virtual void AddSonmething() = 0; //加料
//模板方法
void Make()
{
this->BoilWater();
this->Brew();
this->PourInCup();
this->AddSonmething();
}
};
//制作茶水
class Tea : public DrinkTemplate
{
public:
virtual void BoilWater()
{
cout << "煮开水!" << endl;
}
virtual void Brew()
{
cout << "冲泡茶叶!" << endl;
}
virtual void PourInCup()
{
cout << "茶水倒入杯中!" << endl;
}
virtual void AddSonmething()
{
cout << "加入柠檬!" << endl;
}
};
//制作咖啡
class Coffee : public DrinkTemplate
{
public:
virtual void BoilWater()
{
cout << "煮开水!" << endl;
}
virtual void Brew()
{
cout << "冲泡咖啡!" << endl;
}
virtual void PourInCup()
{
cout << "咖啡倒入杯中!" << endl;
}
virtual void AddSonmething()
{
cout << "加入牛奶!" << endl;
}
};
void test01()
{
DrinkTemplate* tea = new Tea;
tea->Make();
cout << "-----------------" << endl;
DrinkTemplate* coffee = new Coffee;
coffee->Make();
delete tea;
delete coffee;
}
int main() {
test01();
system("pause");
return EXIT_SUCCESS;
}
模板方法的优缺点
优点:
(1)在父类中形式化地定义一个算法,而由它的子类来实现细节的处理,在子类实现详细的处理算法时并不会改变算法中步骤的执行次序。
(2)模板方法模式是一种代码复用技术,它在类库设计中尤为重要,它提取了类库中的公共行为,将公共行为放在父类中,而通过其子类来实现不同的行为,它鼓励我们恰当使用继承来实现代码复用。
(3)可实现一种反向控制结构,通过子类覆盖父类的钩子方法来决定某一特定步骤是否需要执行。
(4)在模板方法模式中可以通过子类来覆盖父类的基本方法,不同的子类可以提供基本方法的不同实现,更换和增加新的子类很方便,符合单一职责原则和开闭原则。
缺点:
需要为每一个基本方法的不同实现提供一个子类,如果父类中可变的基本方法太多,将会导致类的个数增加,系统更加庞大,设计也更加抽象。
适用场景
(1)具有统一的操作步骤或操作过程;
(2) 具有不同的操作细节;
(3) 存在多个具有同样操作步骤的应用场景,但某些具体的操作细节却各不相同;
在抽象类中统一操作步骤,并规定好接口;让子类实现接口。这样可以把各个具体的子类和操作步骤解耦合。