Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.(模板方法模式在一个方法中定义一个算法骨架,并将某些步骤推迟到子类中实现。模板方法模式可以让子类在不改变算法整体结构的情况下,重新定义算法中的某些步骤。)

这里的 “算法” ,也可以理解为广义上的 “业务逻辑” ,并不特指数据结构和算法中的 “算法” 。这里的算法骨架就是 “模板” ,包含算法骨架的方法就是 “模板方法” ,这也是模板方法模式名字的由来。

模板方法模式实现

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

public abstract class AbstractClass {
public final void templateMethod() {
//...
method1();
//...
method2();
//...
}

protected abstract void method1();
protected abstract void method2();
}

public class ConcreteClass1 extends AbstractClass {
@Override
protected void method1() {
//...
}

@Override
protected void method2() {
//...
}
}

public class ConcreteClass2 extends AbstractClass {
@Override
protected void method1() {
//...
}

@Override
protected void method2() {
//...
}
}

AbstractClass demo = ConcreteClass1();
demo.templateMethod();

使用场景

(复用、扩展)

  1. 多个子类有公有的方法,并且逻辑基本相同时。
  2. 重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现。
  3. 重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数约束其行为。

模板模式把一个算法中不变的流程抽象到父类的模板方法 templateMethod() 中,将可变的部分 method1()method2() 留给子类 ContreteClass1ContreteClass2 来实现。所有的子类都可以复用父类中模板方法定义的流程代码。

如果不需要把所有的方法都实现一遍,可以写一个 基类 将所有的方法都实现,然后其余子类继承这个 基类,按需重写就可以~

模板模式与Callback回调函数有何区别和联系?

回调的原理解析

A 类事先注册某个函数 F 到 B 类,A 类在调用 B 类的 P 函数的时候,B 类反过来调用 A 类注册给它的 F 函数。这里的 F 函数就是“回调函数”。A 调用 B,B 反过来又调用 A,这种调用机制就叫作“回调”。

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

public interface ICallback {
void methodToCallback();
}

public class BClass {
public void process(ICallback callback) {
//...
callback.methodToCallback();
//...
}
}

public class AClass {
public static void main(String[] args) {
BClass b = new BClass();
b.process(new ICallback() { //回调对象
@Override
public void methodToCallback() {
System.out.println("Call back me.");
}
});
}
}

回调跟模板模式一样,也具有复用和扩展的功能。除了回调函数之外,BClass 类的 process() 函数中的逻辑都可以复用。如果 ICallbackBClass 类是框架代码,AClass 是使用框架的客户端代码,我们可以通过 ICallback 定制 process() 函数,也就是说,框架因此具有了扩展的能力。

回调可以分为同步回调和异步回调(或者延迟回调)。
同步回调指在函数返回之前执行回调函数;
异步回调指的是在函数返回之后执行回调函数。
上面的代码实际上是同步回调的实现方式,在 process() 函数返回之前,执行完回调函数 methodToCallback()
异步回调在类似于支付,用户在发起支付请求之后,一般不会一直阻塞到支付结果返回,而是注册回调接口给三方支付系统,等三方支付系统执行完成之后,将结果通过回调接口返回给用户。
从应用场景上来看,同步回调看起来更像模板模式异步回调看起来更像观察者模式

模板方法回调应用场景是一致的,都是定义好算法骨架,并对外开放扩展点,符合开闭原则;
两者的却别是代码的实现上不同,模板方法是通过继承来实现,是自己调用自己;回调是类之间的组合。

Android 源码中的模板方法模式

看了上面的例子,肯定可以想到 Activity 生命周期吧 ~,只要继承 Activity 子类,生命周期都可以重写,而且会在相应时机执行。

简述Activity生命周期

startActivity启动过程分析

感谢

设计模式之美

《Android 源码设计模式解析与实战》

以及上文中的链接