Template Methods 模板方法:定义一个操作中的算法的骨架,而再将一些步骤延迟到子类中,TemplateMethod 使得子类不改变一个算法的结构即可重定义该算法的某特定步骤。TemplateMethos 模式解决的是和 Strategy 模式类似的问题,Template 将逻辑算法框架放在抽象基类中,并定义好细节的接口,子类中实现细节,即用继承的方式实现。而 Strategy 模式将逻辑算法封装到一个类中,并采取组合(委托)的方式解决问题。
TemplateMethod 模板方法适用于:1.一次性实现一个算法的不变部分,并将可变的行为留给子类来实现。2.各子类中公共的行为应该被提取出来并集中到一个公共父类中以避免代码重复。3.控制子类扩展,模板方法只在特定点调用钩子操作“hook”,这样允许在这些点进行扩展。
TemplateMethod 模板方法模式的通用结构如下:
参与者:
AbstractClass:定义抽象的原语操作(primitive operation),具体的子类将重定义它们以实现一个算法的各个步骤。实现一个模板方法,定义一个算法的骨架,该模板方法不仅调用原语操作,也调用定义在 AbstractClass 或其它对象中的操作。
ConcreteClass:实现原语操作以完成算法中特定于子类相关的步骤。
ConcreteClass 靠 AbstractClass 实现算法中不变的步骤。模板方法是一种代码利用技术,在类库中尤为重要,它们提取了类库中的公共行为。
关于钩子操作(hook operation):它提供了缺省的行为,子类可以在必要时进行扩展,一个钩子操作在缺省操作通常是一个空操作。ParentClass 本身的 HookOperation 什么也不做:
void ParentClass::HookOperation(){ }
void ParentClass::Operation(){
//父类的操作
HookOperation();
}
//子类可以重定义这个钩子操作
void DerivedClass::HookOperation(){
//子类的扩展
}
钩子操作是面向对象系统中分析和设计的一个原则:DIP(依赖倒置,Dependency Inversion Principles),获得一种反向控制的效果,其含义是父类调用子类的操作(高层模块调用低层模块的操作),低层模块实现高层模块声明的接口。这样控制权在高层模块,低层模块反而要依赖高层模块。
TemplateMethods 模板方法代码示例:
1: //TemplateMethod.h
2: #pragma once
3:
4: // 抽象基类,定义算法的轮廓
5: class AbstractClass
6: {
7: public:
8: AbstractClass(){}
9: virtual ~AbstractClass(){}
10:
11: // 这个函数中定义了算法的轮廓
12: void TemplateMethod();
13: protected:
14: // 纯虚函数,由派生类实现之
15: virtual void PrimitiveOperation1() = 0;
16: virtual void PrimitiveOperation2() = 0;
17: };
18:
19: // 继承自AbstractClass,实现算法
20: class ConcreateClassA : public AbstractClass
21: {
22: public:
23: ConcreateClassA(){}
24: virtual ~ConcreateClassA(){}
25:
26: protected:
27: virtual void PrimitiveOperation1();
28: virtual void PrimitiveOperation2();
29: };
30:
31: // 继承自AbstractClass,实现算法
32: class ConcreateClassB : public AbstractClass
33: {
34: public:
35: ConcreateClassB(){}
36: virtual ~ConcreateClassB(){}
37:
38: protected:
39: virtual void PrimitiveOperation1();
40: virtual void PrimitiveOperation2();
41: };
1:
2: #include "TemplateMethod.h"
3: #include <iostream>
4:
5: void AbstractClass::TemplateMethod()
6: {
7: PrimitiveOperation1();
8: PrimitiveOperation2();
9: }
10: /
11: void ConcreateClassA::PrimitiveOperation1()
12: {
13: std::cout << "PrimitiveOperation1 by ConcreateClassA"
14: << std::endl;
15: }
16:
17: void ConcreateClassA::PrimitiveOperation2()
18: {
19: std::cout << "PrimitiveOperation2 by ConcreateClassA"
20: << std::endl;
21: }
22:
23:
24: void ConcreateClassB::PrimitiveOperation1()
25: {
26: std::cout << "PrimitiveOperation1 by ConcreateClassB"
27: << std::endl;
28: }
29:
30: void ConcreateClassB::PrimitiveOperation2()
31: {
32: std::cout << "PrimitiveOperation2 by ConcreateClassB"
33: << std::endl;
34: }
35:
1: //test.cpp
2: #include "TemplateMethod.h"
3: #include <iostream>
4:
5: int main()
6: {
7: AbstractClass* pConcreateClassA = new ConcreateClassA;
8: AbstractClass* pConcreateClassB = new ConcreateClassB;
9:
10: pConcreateClassA->TemplateMethod();
11: pConcreateClassB->TemplateMethod();
12:
13: delete pConcreateClassA;
14: delete pConcreateClassB;
15:
16: return EXIT_SUCCESS;
17: }