意图
- 定义一个操作中的算法的骨架(稳定),而将一些步骤延迟(变化)到子类中。Template Methond使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
——《设计模式》GOF
适用性
- 一次性实现一个算法的不变的部分,并将可变的行为留给子类实现。
- 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。
- 控制子类扩展。
结构
参与者
-
AbstractClass
-
定义抽象的primitive operation,具体的子类将重定义它们以实现一个算法的各步骤。
-
实现一个模板方法,定义一个算法的骨架。该模板不仅调用原语操作,也调用定义在AbstractClass或其它对象中的操作。
-
ConcreteClass
-
实现原语操作靠AbstractionClass来实现算法中不变的步骤。
协作
-
ConcreteClass靠AbstractionClass来实现算法中不变的步骤。
效果
模板方法调用下列类型的操作:
- 具体的操作(ConcreteClass或对客户类的操作)
- 具体的AbstractionClass的操作(即,对子类的有用的操作)
- 原语操作(即,抽象操作)
- 钩子操作(hook operation),它提供了缺省的行为,子类可以在必要时进行扩展,一个钩子操作在缺省操作通常是一个空操作。
实现
有三个实现问题值得注意:
- 使用C++访问控制 :在C++中,一个模板方法调用的原语操作可以被定义为保护成员。这保证它们只被模板方法调用。必须重定义的原语操作须定义为纯虚函数。模板方法自身不需被重定义;因此可以将模板方法定义为一个非虚成员函数
- 尽量减少原语操作 定义模板的一个重要目的是尽量减少一个子类具体实现该算法时必须重定义的那些原语操作的数目。需要重定义的操作越多,客户程序就越冗长。
- 命名约定 可以给应被重定义的那些操作的名字加上一个前缀以识别它们。
代码
class TemplateMethodStructure
{
public void Test()
{
AbstractionClass ac = new ConcreteClass();
ac.TemplateMethod();
}
}
abstract class AbstractionClass
{
public void TemplateMethod()
{
operation1();
operation2();
}
public abstract void operation1();
public abstract void operation2();
}
class ConcreteClass : AbstractionClass
{
public override void operation1()
{
Console.WriteLine(this.GetType().Name+"----operation1");
}
public override void operation2()
{
Console.WriteLine(this.GetType().Name + "----operation2");
}
}
相关模式
Factory Method模式常被模板方法调用。Strategy模式使用委托来改变整个算法,而模板方法用继承来改变算法的一部分。