一 使用场景
很多事情抽取共同点后是有固定的流程的。比如炒菜,无论超什么菜都是“切菜–》入锅放佐料–》盛菜”。把这些固定的流程抽象到父类然后放到子类里面去实现,便是模板方法模式。
二 定义
模板方法模式Template Method Pattern:定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
AbstractClass抽象类:在抽象类中定义了一系列基本操作,这些基本操作可以是具体的,也可以是抽象的,每一个基本操作对应算法的一个步骤,在其子类中可以重定义或实现这些步骤。同时,在抽象类中实现了一个模板方法(Template Method),用于定义一个算法的框架,模板方法不仅可以调用在抽象类中实现的基本方法,也可以调用在抽象类的子类中实现的基本方法,还可以调用其他对象中的方法。
(2) ConcreteClass具体子类:它是抽象类的子类,用于实现在父类中声明的抽象基本操作以完成子类特定算法的步骤,也可以覆盖在父类中已经实现的具体基本操作。
三 C++实现
Dish.h
#pragma once
#include <string>
#include <iostream>
using namespace std;
class Dish
{
public:
Dish(){}
virtual ~Dish(){}
void templateMethod(){
cutVegtable(); //固定流程切菜
putSeasoning(); // 放佐料
getDish(); // 盛菜
};
virtual void cutVegtable() = 0;
virtual void putSeasoning() = 0;
virtual void getDish() = 0;
};
class SpicyTofo:public Dish // 做个麻辣豆腐
{
public:
SpicyTofo(){}
virtual ~SpicyTofo(){}
void cutVegtable(){
std::cout << "cut tofo\n" << std::endl;
}
void putSeasoning(){
std::cout << "put many cayenne\n" << std::endl;
}
void getDish(){
std::cout << "put tofo into a dish\n" << std::endl;
}
};
class CuminLamb:public Dish // 做个孜然羊肉
{
public:
CuminLamb(){}
virtual ~CuminLamb(){}
void cutVegtable(){
std::cout << "cut lamb\n" << std::endl;
}
void putSeasoning(){
std::cout << "put little Cumin\n" << std::endl;
}
void getDish(){
std::cout << "put lamb into a dish\n" << std::endl;
}
};
main.cpp
#include <iostream>
#include "Dish.h"
using namespace std;
int main()
{
SpicyTofo * spicytofo = new SpicyTofo();
spicytofo->templateMethod();
CuminLamb * cuminlamb = new CuminLamb();
cuminlamb->templateMethod();
delete spicytofo;
spicytofo = NULL;
delete cuminlamb;
cuminlamb = NULL;
system("pause");
return 0;
}
运行结果
四 总结
优点
1 在父类中形式化地定义一个算法,而由它的子类来实现细节的处理,在子类实现详细的处理算法时并不会改变算法中步骤的执行次序。
2 它提取了类库中的公共行为,恰当使用继承可以实现代码复用。
3 可实现一种反向控制结构,通过子类覆盖父类的钩子方法来决定某一特定步骤是否需要执行。
4 在模板方法模式中可以通过子类来覆盖父类的基本方法,不同的子类可以提供基本方法的不同实现,更换和增加新的子类很方便,符合单一职责原则和开闭原则。
缺点
需要为每一个基本方法的不同实现提供一个子类,如果父类中可变的基本方法太多,将会导致类的个数增加。