介绍
重构必备,抽取基类,应对变化。书中说到,确定步骤执行顺序,但是某些步骤的具体实现是未知的,或者说实现是会随着环境变化而改变的。这里很明确了,例如,简单吃饭步骤。端起饭碗->夹菜->吃。在夹菜这个步骤就可能变化了,有的是夹肉,有的夹素菜。但端碗和吃是固定的,就可以抽取到基类中,而夹菜这个步骤可以抽象让子类去实现。
该模式的定义为,定义操作框架,将某些步骤延迟到子类中,使得子类可以不改变算法结构情况下即可重定义算法的某些特定步骤。
在Android中AsyncTask中的回调,还有咱们Activity的生命周期都是模版模式的体现。
UML
使用场景
- 多个子类有公有方法,并且逻辑基本相同的时候。(重构场景)
- 重要,复杂的算法,可以把核心算法设计为模版方法,周边相关细节由子类实现
事例
就借用吃饭这个例子来说明:
- 建立一个抽象的吃步骤:
- 端起碗
- 夹菜
- 开始吃
- 执行整个流程的开始方法
/**
* 模版模式吃饭操作
*/
public abstract class AbsEating {
/**
* 端起碗
*/
public void pickOnBowl() {
System.out.println("端起碗");
}
/**
* 夹菜
*/
public void pickSomething() {
System.out.println("夹菜");
}
/**
* 吃
*/
public void eating() {
System.out.println("开吃吃");
}
/**
* 开始吃饭
*/
public void startEating() {
System.out.println("开始吃");
pickOnBowl();
pickSomething();
eating();
System.out.println("结束吃");
}
}
- 小明吃饭步骤实现:
- 重写拿起碗步骤,在其后再添加不要筷子
- 重写夹菜步骤,改为夹肉
/**
* 小明吃饭
*/
public class XiaoMingTemplate extends AbsEating {
@Override
public void pickOnBowl() {
super.pickOnBowl();
System.out.println("不要筷子");
}
@Override
public void pickSomething() {
System.out.println("夹肉");
}
}
- 小明吃饭步骤实现:
- 重写吃步骤
/**
* 小白吃饭
*/
public class XiaoBaiTemplate extends AbsEating {
@Override
public void eating() {
System.out.println("心情不好,不吃了");
}
}
- 测试方法:
public static void main(String[] arg) {
//小明吃饭
AbsEating absEatingXiaoM = new XiaoMingTemplate();
absEatingXiaoM.startEating();
//小白吃饭
AbsEating absEatingXiaoB = new XiaoBaiTemplate();
absEatingXiaoM.startEating();
}
- 输出:
开始吃
端起碗
不要筷子
夹猪肉
开吃吃
结束吃
开始吃
端起碗
夹菜
心情不好,不吃了
结束吃
从输出可以看到,步骤是定的,但是最后输出确因实际的个体而异,这样就是一个简单的模版模式了,其中的被子类复写的方法则为模版方法。
总结:重构必用,重构过程中会用到上移函数的方式来移动方法到父类,那不就是用了这个的思想吗?这个模式在不知不觉中就被用到了,哈哈哈。