友情支持

如果您觉得这个笔记对您有所帮助,看在D瓜哥码这么多字的辛苦上,请友情支持一下,D瓜哥感激不尽,😜

支付宝

微信

有些打赏的朋友希望可以加个好友,欢迎关注D 瓜哥的微信公众号,这样就可以通过公众号的回复直接给我发信息。

wx jikerizhi

公众号的微信号是: jikerizhi因为众所周知的原因,有时图片加载不出来。 如果图片加载不出来可以直接通过搜索微信号来查找我的公众号。

24. 模版方法模式

24.1. 定义

根据 GoF 的著名著作 《设计模式》,模板方法模式的定义如下:

模板方法模式(Template Method)

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

— Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides
《设计模式》

24.2. 类图

Diagram

当我们要完成在某一细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同时,我们通常考虑用模板方法模式来处理。

AbstractClass是抽象类,其实也就是一抽象模板,定义并实现了一个模版方法。这个模版方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。

ConcreteClass,实现父类所定义的一个或多个抽象方法。每一个AbstractClass都可以有任意多个ConcreteClass与之对应,而每一个ConcreteClass都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。

模板方法模式是通过把不变行为搬移到超类,去除子类中的重复代码来体现它的优势。

模板方法模式就是提供了一个很好的代码复用平台。

因为有时候,我们会遇到由一系列步骤构成的过程需要执行。这个过程从高层次上看是相同的,但有些步骤的实现可能不同。这时候,我们通常就应该要考虑用模板方法模式了。

当不变的和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现。我们通过模板方法模式把这些行为搬移到单一的地方,这样就帮助子类摆脱重复的不变行为的纠缠。

代码 139. templatemethod/AbstractClass.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
package com.diguage.didp.templatemethod;

/**
 * AbstractClass 类
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-19 17:53:36
 */
public abstract class AbstractClass {
  public final void templateMethod() {
    primitiveOperation1();
    System.out.println("这是模板方法!");
    primitiveOperation2();
  }

  public abstract void primitiveOperation1();

  public abstract void primitiveOperation2();
}
代码 140. templatemethod/Client.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package com.diguage.didp.templatemethod;

/**
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-24
 */
public class Client {
  public static void main(String[] args) {
    AbstractClass c;
    c = new ConcreteClassA();
    c.templateMethod();

    c = new ConcreteClassB();
    c.templateMethod();
  }
}
代码 141. templatemethod/ConcreteClassA.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
package com.diguage.didp.templatemethod;

/**
 * ConcreteClassA 类
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-19 17:53:36
 */
public class ConcreteClassA extends AbstractClass {
  public void primitiveOperation1() {
    System.out.println("具体类A方法1的实现");
  }

  public void primitiveOperation2() {
    System.out.println("具体类A方法2的实现");
  }
}
代码 142. templatemethod/ConcreteClassB.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
package com.diguage.didp.templatemethod;

/**
 * ConcreteClassA 类
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-19 17:53:36
 */
public class ConcreteClassB extends AbstractClass {
  public void primitiveOperation1() {
    System.out.println("具体类B方法1的实现");
  }

  public void primitiveOperation2() {
    System.out.println("具体类B方法2的实现");
  }
}

24.3. 常见示例

  1. java.util.Collections.sort(List<T> list)

  2. java.io.InputStream.skip(long n)

  3. java.io.InputStream.read()

  4. java.util.AbstractList.indexOf(Object o)

  5. 从大视角上来看,编译也算是一个模板方法模式。