设计模式学习之模板方法模式

什么是模板方法模式

模板方法模式(Template Method Pattern)在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法接口的情况下,重新定义算法的某些步骤。

理解模板方法模式

这个模式是用来创建一个算法的模板的。什么是模板呢?其实模板就是一个方法,只不过这个方法可以有很多不同的实现方法而已。更具体地说,这个方法将算法定义成一系列步骤,其中的任何步骤都可以是抽象的,被子类根据实际情况具体实现。这样呢,即可以保证算法的整体结构不变,又可以让子类重新定义自己的算法。

模板方法模式类图

模板方法模式类图

下面分别来说说各部分的作用:

AbstractClass就是一个抽象方法,它定义了一些抽象的方法比如primitiveOperation1()primitiveOperation2(),同时也定义了一个模板方法templateMethod()。模板方法在实现的过程当中使用到了这两个抽象方法,但是模板方法和它们的具体实现解耦了。

ConcreteClass是一个具体的方法,是上面的AbstractClass抽象类的子类,可能不止一个子类。这个类实现具体的操作,当模板方法需要这两个方法的时候就会调用它们。

实例分析-茶饮之道

我们知道现在的奶茶的品类非常的多,有绿茶,红茶,珍珠奶茶,红豆奶茶,还有卡布奇诺等等。这些奶茶是如何被做出来的呢,工具都一样,流程也一样,但是做出来的产品却不同,秘密是什么?其实这里面就藏着我们今天的主角-模板方法模式。

先来分析一下做奶茶需要哪几步?

可以看到这份培训手册中明确说明了咖啡和茶的生产工艺,都是有四个步骤,

  • ,将水烧开
  • ,在开水中把茶或者咖啡熬好
  • ,把茶或者咖啡倒进杯子
  • ,添加一些调味剂

我们可以看到这几步就构成了大多数奶茶的生产流程。但是我们是不是应该将这些步骤封装一下呢?后面有什么新的产品上线就可以让店员快速学习上手。

下面我们看看如何抽象出这个产品:

定义茶品制作方法:

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
package com.qinjiangbo.template.methods;

/**
* Created by IntelliJ IDEA.
* Date: 10/25/15 10:14 PM
* Author: Richard
*/
public abstract class CaffeineBeverage {

// 模板方法,封装了上述的四个步骤
public final void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}

// 具体方法,因为这一步大家都一样
public void boilWater() {
System.out.println("Boiling water...");
}

abstract void brew();

// 具体方法,因为这一步大家都一样
public void pourInCup() {
System.out.println("Pouring in cup...");
}
abstract void addCondiments();

}

茶的制造工艺:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.qinjiangbo.template.methods;

/**
* Created by IntelliJ IDEA.
* Date: 10/25/15 10:22 PM
* Author: Richard
*/
public class Tea extends CaffeineBeverage {

@Override
void brew() {
System.out.println("Steeping the tea...");
}

@Override
void addCondiments() {
System.out.println("Adding the condiments...");
}
}

咖啡的制造工艺:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.qinjiangbo.template.methods;

/**
* Created by IntelliJ IDEA.
* Date: 10/25/15 10:23 PM
* Author: Richard
*/
public class Coffee extends CaffeineBeverage {
@Override
void brew() {
System.out.println("Dripping coffee through filter...");
}

@Override
void addCondiments() {
System.out.println("Adding sugar and Milk...");
}
}

后面其实我们可以依据这个模板写出很多奶茶的制作工艺的,扩展起来非常方便。

实例测试

写了一个测试用例,比较简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.qinjiangbo.template.test;

import com.qinjiangbo.template.methods.Coffee;
import com.qinjiangbo.template.methods.Tea;

/**
* Created by IntelliJ IDEA.
* Date: 10/25/15 10:26 PM
* Author: Richard
*/
public class TeaTest {

public static void main(String[] args) {
Tea tea = new Tea();
tea.prepareRecipe();

System.out.println("Above are about tea, following about coffee:");

Coffee coffee = new Coffee();
coffee.prepareRecipe();
}
}

输出的结果如下:

1
2
3
4
5
6
7
8
9
Boiling water...
Steeping the tea...
Pouring in cup...
Adding the condiments...
Above are about tea, following about coffee:
Boiling water...
Dripping coffee through filter...
Pouring in cup...
Adding sugar and Milk...

结果是符合预期的。

模板方法模式 vs 策略模式

其实大伙儿对模板方法模式和策略模式一直都很容易搞混,因为它们都是来改变一些方法或者策略来实现不同的目的。这里主要主要谈谈它们的不同吧。

  • [目的]模板方法模式的目的是定义一系列方法的一个轮廓,允许子类选择去实现其中的具体步骤;而策略模式的目的是能够定义一系列可以相互替换的算法。
  • [侧重点]模板方法模式更加侧重的是一条算法线上的方法点的多样性,线上的可以被替换的点是一定能够被执行的,只不过每一个点的行为可能不一样而已;但是策略模式更加侧重的是整条算法线的替换,它的各种算发现每次只能执行一条。
  • [方法可见性]模板方法模式中除了模板方法是公开的以外,其他的具体执行的方法点都是对外访问限制的;而策略模式中通常各个方法点都是可以访问到的。
  • [继承组合]模板方法模式基于的是类的继承思想,子类决定父类的某个抽象方法的具体实现;而策略模式基于的是对象的组合,将不同算法的对象组合起来从而实现算法的相互替换。

总结

模板方法模式为我们提供了一组能够替换掉具体方法点的操作思想。其实这种思想在Java的JDK中也有具体的体现,比如Arrays.sort()方法,这个方法里面其实使用的就是模板方法模式,模板方法就是sort()。我们可以利用模板方法提供更为灵活的编码风格。上面最后一点说的[继承组合]不同点其实会有人提出疑问,不是说要多用组合,少用继承嘛?为啥现在还要用?这个问题应该这么来考虑,设计模式的初衷是找到最符合某一类问题的解决方法和模式,这个需要依据具体的情况具体分析,大多数情况下我们还是坚持多用组合,少用继承的思想。

分享到