意图
定义一个操作的算法骨架,将一些步骤延迟(实现)到子类。模板方法允许子类重新定义算法的某些步骤,而不改变算法的结构。
结构
动机
模板方法用一些抽象的操作定义一个算法,通过子类重新定义这些操作以提供具体的行为。
模板方法设定了算法中的各个抽象操作以及它们的先后顺序。
适用性
- 一次性实现算法中的不变性,并将可变的行为留给子类实现;
- 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复;
- 控制子类的扩展。 您可以定义一个在特定点调用的“Hook(钩子)”操作的模板方法,从而允许只在这些点上进行扩展。
实现细节
-
访问控制
模板方法中的原语操作可以定义为抽象受保护(abstract protected)方法,允许子类重新定义。模板方法自身不需要被重定义,因此可定义为普通的公开(public)方法; -
减少原语操作
设计模板方法的一个重要目标是最小化一个子类必须重写的原语操作的数量,从而使算法更加精确; -
命名约定
可以给应该被重定义的那些操作的名字加上一个前缀以识别它们,例如:“Do-”前缀,DoRead,DoCreateDocument。
示例
考虑一个支持在屏幕上绘图的视图(View)。 视图强制其子类在进入“焦点(Focus)” 状态之后,才能进行绘图(例如,颜色和字体)。
实现(C#)
using System;
// 视图抽象基类
public abstract class View
{
// 绘制视图的模板方法
public void Display()
{
// 确保获得焦点
SetFocus();
DoDisplay();
ResetFocus();
}
// 受保护的抽象原语操作
protected abstract void DoDisplay();
// 私有操作,防止子类覆盖此方法绕开规则。
private void SetFocus()
{
Console.WriteLine("{0} 获得焦点" , this.GetType().FullName);
}
// 私有操作,防止子类覆盖此方法绕开规则。
private void ResetFocus()
{
Console.WriteLine("{0} 释放焦点" , this.GetType().FullName);
}
}
public class GridView : View
{
//定义个性化绘图(受保护,不对外公开)
protected override void DoDisplay()
{
Console.WriteLine(" ==>> 开始个性化绘图");
}
}
public class TreeView : View
{
//定义个性化绘图(受保护,不对外公开)
protected override void DoDisplay()
{
Console.WriteLine(" ==>> 开始个性化绘图" );
}
}
public class App
{
public static void Main(string[] args)
{
View gridView = new GridView();
View treeView = new TreeView();
gridView.Display();
treeView.Display();
}
}
// 控制台输出:
// GridView 获得焦点
// ==>> 开始个性化绘图
// GridView 释放焦点
// TreeView 获得焦点
// ==>> 开始个性化绘图
// TreeView 释放焦点