Java设计模式-模板方法模式

首先来看下模板方法的概述:
定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。它是一种类行为型模式,是基于继承的代码复用的基本技术。

这种设计模式非常的简单,同时也是最常见的设计模式之一,但是不能大意,就像单例模式一样,虽然简单,但是有许多细节需要注意

结构&角色

模板方法模式需要开发抽象类具体子类的设计师之间的协作。
一个设计师负责给出一个算法的轮廓和骨架,另一些设计师则负责给出这个算法的各个逻辑步骤。
代表这些具体逻辑步骤的方法称做基本方法(primitive method);而将这些基本方法汇总起来的方法叫做模板方法(template method),这个设计模式的名字就是从此而来。

前面说过,这种模式非常简单,只涉及到两个角色:

  • 抽象模板(Abstract Template)角色
    定义了一个或多个抽象操作,以便让子类实现。这些抽象操作叫做基本操作,它们是一个顶级逻辑的组成步骤。
    定义并实现了一个模板方法。这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。
  • 具体模板(Concrete Template)角色
    每一个抽象模板角色都可以有任意多个具体模板角色与之对应,而每一个具体模板角色都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。

一个栗子

首先定义抽象模板角色:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public abstract class AbstractTemplate {

// 模板方法
// 使用 final 关键字保证算法不会被篡改
public final void prepareExecute(){
// 调用基本方法
Operation1();
Operation2();
hookMethod();
Operation3();
}
// 基本方法声明(由子类实现)
protected abstract void Operation1();

private void Operation2() {
System.out.println("顶级类中的方法执行....");
}

private final void Operation3(){
System.out.println("顶级类方法 final");
}

// 基本方法,空方法--钩子
void hookMethod() {}
}

在方法中,我们可以使用 final 关键字来保证子类继承的时候无法覆盖父类中的算法,也就是说这个抽象类它拥有算法,而且保护这个算法。
下面再来看看具体模板角色,就非常简单了,这个栗子中就需要实现一个算法:

1
2
3
4
5
6
7
8
9
10
11
public class ConcreteTemplate extends AbstractTemplate {
@Override
protected void Operation1() {
System.out.println("子类中的具体实现");
}

@Override
void hookMethod() {
System.out.println("使用钩子....");
}
}

然后稍微测试下就可以了,测试代码就不写了,超简单的

关于钩子

上面的栗子中,我们还定义了一个叫钩子的方法,什么是钩子?
在此设计模式中可以这么理解:一个钩子方法常常由抽象类给出一个空实现作为此方法的默认实现。这种空的钩子方法叫做“Do Nothing Hook”。
作为子类,你可以视情况绝对要不要去覆盖它们(也就是说是可选的),更加常用的是通过钩子来控制某个算法要不要执行,比如:

1
2
3
4
5
6
7
8
9
public final void prepareExecute() {
// 调用基本方法
Operation1();
Operation2();
if (hookMethod()) {
System.out.println("钩子控制的代码被执行....");
Operation3();
}
}

这样就可以通过钩子方法的返回值来决定要不要执行某些算法,应该是比较实用的。
钩子方法的名字应当以 do 开始,这是熟悉设计模式的 Java 开发人员的标准做法。在上面的例子中,钩子方法 hookMethod() 应当以 do 开头;在 HttpServlet 类中,也遵从这一命名规则,如 doGet()、doPost() 等方法。

根据基本设计原则,我们应该将决策权放在高层模块中

应用

实际应用中,JDK 中的排序的功能就是用的模板方法,如果排序一个对象数组( Object[] ),我们实现两个对象的比较,就要实现 Comparable 接口的 compareTo 方法.
Java 的 sort 方法实现就比较像模板方法,首先克隆数组,然后进行一系列的调取算法

在 Java 提供的 Applet 中也使用了大量的钩子来提供行为

与策略模式关系

也会会感觉它和策略模式非常相似,但是其实有着本质的不同,虽然它们都是封装算法,但是一个用组合一个用继承。
策略模式:是定义一个算法家族(具体实现),并让这些算法可以互换。
模板方法:定义一个算法的大纲(算法的步骤),由子类定义其中某些步骤的内容。

模板方法可以定义具体的方法、抽象方法、钩子
或者可以说,工厂方法也是模板方法的一种特殊版本。

参考

http://www.cnblogs.com/java-my-life/archive/2012/05/14/2495235.html

评论框加载失败,无法访问 Disqus

你可能需要魔法上网~~