1.意图
子类在不改变父类的算法结构的情况下,可以重定义算法的某些特定步骤
2.动机
模板方法用一些抽象的操作定义一个算法,子类重定义这些操作以提供具体的行为;步骤的顺序定了,但实现可以调整;
3.适用性
1)一次性实现算法不变部分,并将可变的行为留给子类来实现
2)子类中的公共行为应该被提取出来并集中到一个公共父类中以避免代码重复
3)hook操作,方便子类扩展,定义好hook方法留空,等需要的时候由子类去实现
4.结构
5.参与者
AbstractClass:
定义抽象的原语操作PrimitiveOperation,子类会重写它
定义模板方法,实现算法骨架;模板方法会调用PrimitiveOperation方法,也会调用抽象类中的其他方法
ConcreteClass:
重写PrimitiveOperation,来实现算法细节
6.协作
ConcreteClass靠AbstractClass来实现算法的不变部分,自己实现可变部分
7.效果
1)代码复用的基本技术,常见于类库中提取类库的公共行为
2)导致反向控制,即父类调用子类的方法
3)模板方法会调用如下操作
具体的操作(非抽象类的一些方法,可以是ConcreteClass,也可以是客户类)
具体的AbstractClass操作(AbstractClass的方法,通常会对自己有用)
原语操作PrimitiveOperation,也称抽象操作(必须被重定义)
Factory Method
钩子操作HookOperation(可以被重定义),在抽象类里一般提供缺省操作(空操作),子类在需要的时候可以重定义,也可以不重定义
4)必须在设计的时候明确哪些是原语操作,哪些是钩子操作
5)子类可以继承重写父类方法,但重写的时候又想要先调用父类方法,再加上重写新加的部分,此时很容易忘记调用父类方法,如下
void DerivedClass::Operation(){
ParentClass::Operation(); // 如果有很多子类,这个调用容易遗漏
//***其他要扩展的内容
}
可以用模板方法来实现上面的要求,省去每次都调用父类方法的麻烦
void ParentClass::Operation(){
//** 公共操作
HookOperation();
}
void ParentClass::HookOperation() {} //缺省操作,子类需要就自己重定义
void DerivedClass:HookOperation(){ // ***子类的扩展内容}
8.实现
1).使用C++访问控制:
模板方法调用的原语操作可以定义为protected(只能在类内部调用,不能被外部调用,且派生类也可以访问)
必须重定义的原语操作定义为纯虚函数
模板方法自身不需要重定义,因此模板方法定义为非虚成员函数
2)尽量减少原语操作:因为需要重定义的操作越多,客户程序就越冗长
3)命名约定:如需要被重定义的原语操作可以加前缀 Do,如DoRead
9.日常开发项目应用
地图玩法里面,玩家进入地图操作EnterMap,里面定义了步骤,在父类common_map里定义了DoEnterMap为缺省的操作,子类xxx_map里可以自定义DoEnterMap的内容;