模板方法模式实现要素:准备一个抽象类,将部分逻辑以具体方法的形式实现,然后声明一些抽象方法交由子类实现剩余逻辑,用钩子方法给予子类更大的灵活性。最后将方法汇构成一个不可改变的模板方法。
一、抽象基类
1、基本方法(公用)
2、抽象方法
3、钩子函数:提供一个默认或空的实现,具体的子类可以自行决定是否挂钩以及如何挂钩
4、将基本方法和抽象方法组合成一个模板方法(必须是final修饰,模板方法不允许子类修改)
二、具体子类
1、重写抽象方法
模板方法模式的适用场景:
(1)算法或操作遵循相似的逻辑
(2)重构时(把相同的代码抽取到父类中)
(3)重要、复杂的算法,核心算法设计为模板算法
模板方法模式的优缺点:
优点:封装性好、复用性好、屏蔽细节、便于维护
缺点:必须继承父类
实例展示:
抽象父类:
package com.imooc.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子类:
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子类:
package com.imooc.pattern.template;
/*
* 具体子类,提供了制备茶的具体实现
*/
public class Tea extends RefreshBeverage {
private boolean isCustomerWantsCondiments;
public Tea(){
}
public Tea(boolean isCustomerWantsCondiments){
this.isCustomerWantsCondiments = isCustomerWantsCondiments;
}
@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(){
if(isCustomerWantsCondiments){
return true;
}else{
return false;
}
}
}
测试类:
package com.imooc.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("茶好了!");
System.out.println("\n******************************************");
System.out.println("制备茶...");
RefreshBeverage b3 = new Tea(true);
b3.prepareBeverageTemplate();
System.out.println("茶好了!");
}
}
打印结果:
制备咖啡...
将水煮沸
用沸水冲泡咖啡
将饮料倒入杯中
加入糖和牛奶
咖啡好了!
******************************************
制备茶...
将水煮沸
用80度的热水浸泡茶叶5分钟
将饮料倒入杯中
茶好了!
******************************************
制备茶...
将水煮沸
用80度的热水浸泡茶叶5分钟
将饮料倒入杯中
加入柠檬
茶好了!