模式定义
在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模版方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
模式理解
简单来说就是,模版中定好步骤并实现基本方法,子类实现特定方法。
需要注意的地方:模版方法需要使用final标记以防止其它方法对模版做改动,模版方法的基本实现需要标记为private使得其子类不能修改模版类的最基本实现,模版方法中可拓展实现需标记为抽象的并且为protected。使得只有子类才能实现其可变方法。
模式例子
以冲泡咖啡或茶为例,实现模版方法。
泡咖啡步骤:把水煮沸,冲泡,把饮料倒进杯子,加调料。
泡茶步骤:把水煮沸,用沸水浸泡茶叶,把茶倒进杯子。
模版抽象类(RefreshBeverage.java)
package com.pattern.template;
/*
* 抽象基类,为所有子类提供一个算法框架
*
* 提神饮料
*/
public abstract class RefreshBeverage {
/*
* 制备饮料的模板方法
* 封装了所有子类共同遵循的算法框架
*/
public final void prepareBeverageTemplate(){
//步骤1 将水煮沸
boilWater();
//步骤2 泡制饮料
brew();
//步骤3 将饮料倒入杯中
pourInCup();
if(isCustomerWantsCondiments()){
//步骤4 加入调味料
addCondiments();
}
}
/*
* Hook, 钩子函数,提供一个默认或空的实现
* 具体的子类可以自行决定是否挂钩以及如何挂钩
* 询问用户是否加入调料
*/
protected boolean isCustomerWantsCondiments() {
return true;
}
/*
* 基本方法,将水煮沸
*/
private void boilWater() {
System.out.println("将水煮沸");
}
/*
* 基本方法,将饮料倒入杯中
*/
private void pourInCup() {
System.out.println("将饮料倒入杯中");
}
/*
* 抽象的基本方法,泡制饮料
*/
protected abstract void brew();
/*
* 抽象的基本方法, 加入调味料
*/
protected abstract void addCondiments();
}
咖啡类(Coffee.java)
package com.imooc.pattern.template;
/*
* 具体子类,提供了咖啡制备的具体实现
*/
public class Coffee extends RefreshBeverage {
@Override
protected void brew() {
System.out.println("用沸水冲泡咖啡");
}
@Override
protected void addCondiments() {
System.out.println("加入糖和牛奶");
}
}
茶类(Tea.java)
package com.pattern.template;
/*
* 具体子类,提供了制备茶的具体实现
*/
public class Tea extends RefreshBeverage {
@Override
protected void brew() {
System.out.println("用80度的热水浸泡茶叶5分钟");
}
@Override
protected void addCondiments() {
System.out.println("加入柠檬");
}
@Override
/*
* 子类通过覆盖的形式选择挂载钩子函数
* @see com.imooc.pattern.template.RefreshBeverage#isCustomerWantsCondiments()
*/
protected boolean isCustomerWantsCondiments(){
return false;
}
}
测试类(RefreshBeverageTest.java)
package com.pattern.template;
public class RefreshBeverageTest {
public static void main(String[] args) {
System.out.println("制备咖啡...");
RefreshBeverage b1 = new Coffee();
b1.prepareBeverageTemplate();
System.out.println("咖啡好了!");
System.out.println("\n******************************************");
System.out.println("制备茶...");
RefreshBeverage b2 = new Tea();
b2.prepareBeverageTemplate();
System.out.println("茶好了!");
}
}
模式适用场景
算法或操作遵循相同的逻辑;
重构中提取相同功能代码做成模版;
重要或复杂的代码。
模式优缺点
优点:封装性好,复用性好,屏蔽细节,便于维护。
缺点:继承,已经有继承的类不好做模版方法的重构。