1 定义
模板方法模式(Template Method Pattern)又简称模板模式,属于行为型设计模式,它主要是在父类中定义一个统一的操作的算法框架,而将具体实现延迟到子类中,使得不同的子类按照父类已定义好的框架结构进行实现不同的算法细节。这类行为的思想实现也就是控制反转(Inversion of Control,缩写IOC)的体现。例如现实场景中煮饭,所有人都公知同样的步骤:洗米、放水和煮法,不同的人或不同的工具煮出来味道也是会不一样的。
2 实现
模板方法模式一般包含了2个角色,分别是:
- 抽象父类(AbstractClass):用于定义算法的骨架。例如上述定义举例煮饭中的洗米、放水和煮法。
- 具体实现子类(ConcreteClass):继承抽象父类,实现父类中的抽象方法。例如上述定义举例的煮饭的实际实现。
抽象父类,提供一个统一的调用入口方法,方法内进行所有抽象方法的调用:
public abstract class Cook {
protected abstract void wash();
protected abstract void addWater();
protected abstract void mode();
public void cook() {
wash();
addWater();
mode();
}
}
具体实现子类,实现父类所声明的抽象方法,它是具体算法的实现:
public class CasseroleCook extends Cook {
@Override
protected void wash() {
System.out.println("用砂锅洗米");
}
@Override
protected void addWater() {
System.out.println("凭感觉加适量的水");
}
@Override
protected void mode() {
System.out.println("猛火煮出锅巴");
}
}
public class RiceCookerCook extends Cook {
@Override
protected void wash() {
System.out.println("用电饭煲洗米");
}
@Override
protected void addWater() {
System.out.println("对应刻度加适量的水");
}
@Override
protected void mode() {
System.out.println("一键香甜柴火饭");
}
}
客户端:
public class Main {
public static void main(String[] args) {
Cook riceCookerCook = new RiceCookerCook();
riceCookerCook.cook();
Cook casseroleCook = new CasseroleCook();
casseroleCook.cook();
}
}
输出结果:
用电饭煲洗米
对应刻度加适量的水
一键香甜柴火饭
用砂锅洗米
凭感觉加适量的水
猛火煮出锅巴
2.1 钩子函数
钩子就是给子类一个授权,让子类自己可以来决定模板方法中的某此逻辑是否一定要执行。就比如上述示例中,我们可以让去砂锅煮饭时加上一些腊味来实现特色煲仔饭。
抽象父类:
public abstract class Cook {
protected abstract void wash();
protected abstract void addWater();
protected abstract void mode();
protected abstract boolean isAddAccessories();
protected abstract void addAccessories();
public void cook() {
wash();
addWater();
if (isAddAccessories()) {
addAccessories();
}
mode();
}
}
具体实现子类:
public class CasseroleCook extends Cook {
@Override
protected void wash() {
System.out.println("用砂锅洗米");
}
@Override
protected void addWater() {
System.out.println("凭感觉加适量的水");
}
@Override
protected void mode() {
System.out.println("猛火煮出锅巴");
}
@Override
protected boolean isAddAccessories() {
return true;
}
@Override
protected void addAccessories() {
System.out.println("加一些腊味");
}
}
public class RiceCookerCook extends Cook {
@Override
protected void wash() {
System.out.println("用电饭煲洗米");
}
@Override
protected void addWater() {
System.out.println("对应刻度加适量的水");
}
@Override
protected void mode() {
System.out.println("一键香甜煲火饭");
}
@Override
protected boolean isAddAccessories() {
return false;
}
@Override
protected void addAccessories() {
}
}
客户端:
public class Main {
public static void main(String[] args) {
Cook riceCookerCook = new RiceCookerCook();
riceCookerCook.cook();
Cook casseroleCook = new CasseroleCook();
casseroleCook.cook();
}
}
输出结果:
用电饭煲洗米
对应刻度加适量的水
一键香甜煲火饭
用砂锅洗米
凭感觉加适量的水
加一些腊味
猛火煮出锅巴
3 总结
模板方法模式其实就是当不变和可变的行为在方法的子类实同中混合在一起时,将相同一系列行为步骤搬移到父类进行定义,去除子类中重复的代码,子类只保留不变的行为的实现细节逻辑。
模板方法模式其实是控制反转思想的实现。通过父类调用其子类的操作,子类对父类进行扩展行为,所以往往这样也会导致一定程度上代码阅读的难度。就如传统的程序开发中往往是从main 函数开始,调用各种各样的库来完成一个程序,这样开发者控制着整个运行过程。而如果使用的是框架开发时,框架就变成了控制着整个运行过程。正如Android开发中,我们大多情况下不必关心main函数什么时候开始,只需要知道Activity的onCreate、onStart等生命周期的回调,onCreate 名称是不能修改的,但我们需要对其进行实现逻辑,因为使用了框架,享受框架带来福利的同时,就要遵循框架的规则。所以说,模板方法模式是所有框架最基本的特征。