模板方法模式的实现要素:
抽象基类:1、基本方法 2、抽象方法 3、可选的钩子 4、Template方法(final)不能被子类覆写
具体子类:1、实现基类中的抽象方法 2、覆盖钩子方法
总结:准备一个抽象类,将部分逻辑以具体方法的形式实现,然后声明一些抽象方法交由子类实现剩余逻辑,用钩子方法给予子类更大的灵活性。最后将方法汇总构成一个不可改变的模板方法。
模板方法模式的适用场景:
1、算法或操作逻辑遵循相似的逻辑
2、重构时(把相同的代码抽取到父类中)
3、重要、复杂的算法,核心算法设计为模板算法
模板方法模式的优点:
1、封装性好
2、复用性好
3、屏蔽细节
4、便于维护
模板方法模式的缺点:
1、继承(java是单继承的语言)
行业案例;
通信行业的种类繁多数量巨大的日志——抽取共性——获得规律(获得文件,打开文件 ,读取日志结构,处理单行日志(延迟到子类实现),清理工作)
案例:
新建一个基类:泡制提神饮料
package net.dalimo.template;
/*
* 抽象基类,为所有子类提供一个算法框架
*
* 提神饮料
*/
public abstract class RefreshBeverage {
/*
* 制备饮料的模板方法
* 封装了所有子类共同遵循的算法框架
*/
public final void prepareBeverageTemplate(){
//步骤1:
boilWater();
//搅拌
brew();
//倒入杯中
pourInCup();
//加入调料
addCondiments();
}
/**
* 基本方法,将水煮沸
*/
private void boilWater() {
System.out.println("将水煮沸");
}
/**
* 抽象的基本方法,泡制饮料
*/
protected abstract void brew();
private void pourInCup() {
System.out.println("倒入杯中");
}
protected abstract void addCondiments();
}
新建一个子类:泡制咖啡
package net.dalimo.template;
/*
* 具体子类,提供了咖啡制备的具体实现
*/
public class Coffee extends RefreshBeverage {
@Override
protected void brew() {
System.out.println("用沸水冲泡咖啡");
}
@Override
protected void addCondiments() {
System.out.println("加入糖和牛奶");
}
}
引入 钩子方法的概念:泡制不加调料的茶
1、修改基类,加入判断条件
package net.dalimo.template;
/*
* 抽象基类,为所有子类提供一个算法框架
*
* 提神饮料
*/
public abstract class RefreshBeverage {
/*
* 制备饮料的模板方法
* 封装了所有子类共同遵循的算法框架
*/
public final void prepareBeverageTemplate(){
//步骤1:
boilWater();
//搅拌
brew();
//倒入杯中
pourInCup();
//加入调料
if(isCustomerWantsCondiments()){
addCondiments();
}
}
/**
* Hook,钩子函数,提供一个默认或空的实现
* 具体的子类可以自行决定是否挂钩以及如何挂钩
* 询问用户是否加入调料
* @return
*/
protected boolean isCustomerWantsCondiments() {
return true;
}
/**
* 基本方法,将水煮沸
*/
private void boilWater() {
System.out.println("将水煮沸");
}
/**
* 抽象的基本方法,泡制饮料
*/
protected abstract void brew();
private void pourInCup() {
System.out.println("倒入杯中");
}
protected abstract void addCondiments();
}
新建一个子类:泡制茶
package net.dalimo.template;
/**
* 具体子类,提供了制备茶的具体实现
* @author allensean
*
*/
public class Tea extends RefreshBeverage {
@Override
protected void brew() {
System.out.println("用80度的热水浸泡茶叶5分钟");
}
@Override
protected void addCondiments() {
System.out.println("加入柠檬");
}
/**
* 子类通过覆写的形式选择挂载钩子函数
* @see
*/
@Override
protected boolean isCustomerWantsCondiments() {
return false;
}
}
package net.dalimo.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("茶好了");
}
}