什么是模板方法?即让工作或流程顺序按照写好的模板进行下去,同时还可以自定义流程,以及简化流程。
举例:冲泡茶和咖啡均分四步进行:
- 把水煮沸
- 冲泡咖啡(茶)
- 把咖啡(茶)倒入杯子
- 加糖(柠檬)
一般写法
咖啡类
public class Coffee {
public void prepare() {
/**
* 制作咖啡:
* 1。 把水煮沸
* 2。 用水冲泡
* 3。 把咖啡倒进杯子
* 4。 加糖
*/
boilWater();
brewCoffee();
pourInCup();
addSuger();
}
public void boilWater() {
System.out.println("把水煮沸");
}
public void brewCoffee() {
System.out.println("用水冲泡咖啡");
}
public void pourInCup() {
System.out.println("把咖啡倒进杯子");
}
public void addSuger() {
System.out.println("加糖");
}
}
茶类
public class Tea {
public void prepare() {
/**
* 制作茶:
* 1。 把水煮沸
* 2。 用水冲泡
* 3。 把茶倒进杯子
* 4。 加柠檬
*/
boilWater();
pourInCup();
pourInCup();
addLemon();
}
public void boilWater() {
System.out.println("把水煮沸");
}
public void brewTea() {
System.out.println("用水冲泡茶");
}
public void pourInCup() {
System.out.println("把茶倒进杯子");
}
public void addLemon() {
System.out.println("加柠檬");
}
}
测试类
public class Test01 {
/**
* 这种实现方式有很多重复的代码
*/
public static void main(String[] args) {
Coffee coffee = new Coffee();
Tea tea = new Tea();
coffee.prepare();
System.out.println("---------------");
tea.prepare();
}
}
模板方法
定义抽象的模板方法,把公共方法抽离出来,其它交给子类去实现
public abstract class DrinksTemplate {
/**
* 设定为final,不让子类去覆盖或篡改流程
*/
final public void prepare() {
boilWater();
brew();
pourInCup();
add();
}
public void boilWater() {
System.out.println("把水煮沸");
}
/**
* 交给子类实现
*/
public abstract void brew();
public void pourInCup() {
System.out.println("把饮料倒进杯子");
}
public abstract void add();
}
咖啡类
public class Coffee extends DrinksTemplate {
@Override
public void brew() {
System.out.println("用沸水冲泡咖啡");
}
@Override
public void add() {
System.out.println("加糖");
}
}
茶类
public class Tea extends DrinksTemplate {
@Override
public void brew() {
System.out.println("用沸水冲泡茶");
}
@Override
public void add() {
System.out.println("加柠檬");
}
}
测试类
public class Test01 {
public static void main(String[] args) {
Coffee coffee = new Coffee();
Tea tea = new Tea();
coffee.prepare();
System.out.println("-----------");
tea.prepare();
}
}
使用钩子函数
钩子函数是在抽象模板方法中定义的,它的作用就是控制流程中的某个步骤是否执行、简化流程,子类可以选择覆盖。比如,在准备给用户冲泡咖啡或茶之前询问用户是否需要加糖或者柠檬,不需要就不进行加糖或柠檬这一步骤了。
抽象模板方法
public abstract class DrinksTemplate {
/**
* 设定为final,不让子类去覆盖或篡改流程
*/
final public void prepare() {
boilWater();
brew();
pourInCup();
if (ifAdd()) {
add();
}
}
public void boilWater() {
System.out.println("把水煮沸");
}
/**
* 交给子类实现
*/
public abstract void brew();
public void pourInCup() {
System.out.println("把饮料倒进杯子");
}
public abstract void add();
/**
* 钩子函数
*/
public Boolean ifAdd() {
return true;
}
}
只让茶类去覆盖钩子函数
@Data
public class Tea extends DrinksTemplate {
private Boolean ifAdd;
@Override
public void brew() {
System.out.println("用沸水冲泡茶");
}
@Override
public void add() {
System.out.println("加柠檬");
}
@Override
public Boolean ifAdd() {
return ifAdd;
}
}
测试类
@SuppressWarnings("Duplicates")
public class Test01 {
public static void main(String[] args) {
Coffee coffee = new Coffee();
Tea tea = new Tea();
// 启用钩子函数
tea.setIfAdd(false);
coffee.prepare();
System.out.println("==========");
tea.prepare();
}
}
测试结果
把水煮沸
用沸水冲泡咖啡
把饮料倒进杯子
加糖
==========
把水煮沸
用沸水冲泡茶
把饮料倒进杯子