1. 定义
模板方法模式是类的行为模式。准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。这就是模板方法模式的用意。
简单理解
- 模板方法
一个模板方法是定义在抽象类中的,把基本操作方法组合在一起形成一个总算法或一个总行为的方法。
一个抽象类可以有任意多个模板方法,而不限于一个。每一个模板方法都可以调用任意多个具体方法。 - 基本方法
基本方法又可以分为三种:抽象方法(Abstract Method)、具体方法(Concrete Method)和钩子方法(Hook Method)。
● 抽象方法:一个抽象方法由抽象类声明,由具体子类实现。在Java语言里抽象方法以abstract关键字标示。
● 具体方法:一个具体方法由抽象类声明并实现,而子类并不实现或置换。
● 钩子方法:一个钩子方法由抽象类声明并实现,而子类会加以扩展。通常抽象类给出的实现是一个空实现,作为方法的默认实现。 - 默认钩子方法
一个钩子方法常常由抽象类给出一个空实现作为此方法的默认实现。这种空的钩子方法叫做“Do Nothing Hook”。显然,这种默认钩子方法在缺省适配模式里面已经见过了,一个缺省适配模式讲的是一个类为一个接口提供一个默认的空实现,从而使得缺省适配类的子类不必像实现接口那样必须给出所有方法的实现,因为通常一个具体类并不需要所有的方法。
2. 简单实例
假如你是一个店员,店理由咖啡和茶,你为顾客准备不同的饮品的时候,基本方法如下:
- 准备沸水
- 用沸水冲泡咖啡或茶叶
- 用合适的杯子把咖啡或者茶装起来
- 加上一些合适的调料
很显然,上面四个步骤中步骤1和3都是一样的,沸水、杯子;步骤2和4不同,咖啡或者茶叶、抹茶或者奶盖;
所以我们可以把相同的步骤放到基类,把不同的步骤让子类去实现,另外加个钩子函数,让子类去重写,实现不同的逻辑;
3. 具体代码实现
- 首先把共同的方法封装在基类中
"Drink作为一个父类,把共通的方法定义并实现,子类不能去修改;然后定义抽象的方法,让子类去实现。"
public abstract class Drink {
public void prepareDrink() {
BoilingWater();
Brewing();
cups();
if (isAddOthers()) {
seasoning();
}
}
//沸水
private void BoilingWater() {
System.out.println("BoilingWater 水已经沸腾了。。。");
}
//冲泡咖啡或者茶,具体子类去实现
public abstract void Brewing();
//都用杯子装起来
private void cups() {
System.out.println("cups 找个杯子装起来。。。");
}
//子类决定加什么调料
public abstract void seasoning();
public boolean isAddOthers() {
return true;
}
}
- 不同的子类,继承父类,并实现自己的逻辑
"咖啡:拿铁、奶"
public class Coffee extends Drink{
@Override
public void Brewing() {
System.out.println("Brewing 来一杯拿铁...");
}
@Override
public void seasoning() {
System.out.println("seasoning 拿铁多加点奶...");
}
}
"茶:红茶、奶盖"
public class Tea extends Drink{
@Override
public void Brewing() {
System.out.println("Brewing 我们来一壶红茶...");
}
@Override
public void seasoning() {
System.out.println("seasoning 红茶加点奶盖吧...");
}
@Override
public boolean isAddOthers() {
//子类可以重写该方法,来决定是不是添加其他的东西
return true;
}
}
- 调用方式
//茶
Tea tea = new Tea();
tea.prepareDrink();
//咖啡
Coffee coffee = new Coffee();
coffee.prepareDrink();
- 输出结果
"茶"
I/System.out(25585): BoilingWater 水已经沸腾了。。。
I/System.out(25585): Brewing 我们来一壶红茶...
I/System.out(25585): cups 找个杯子装起来。。。
I/System.out(25585): seasoning 红茶加点奶盖吧...
"咖啡"
I/System.out(25585): BoilingWater 水已经沸腾了。。。
I/System.out(25585): Brewing 来一杯拿铁...
I/System.out(25585): cups 找个杯子装起来。。。
I/System.out(25585): seasoning 拿铁多加点奶...
4. 总结
模板方法模式总结起来就是:父类定义并实现公共的方法,并且子类不能修改;对于子类之间的差异,增加抽象的方法,让子类去实现自己的逻辑,互不干扰;并且子类可以通过重写父类的特定方法(上面的钩子方法),来决定是否执行某个步骤或者方法。