模板方法模式 (Template)
场景问题
问题案例
考虑一个制作饮品的流程,制作咖啡和茶都需要烧水、冲泡、倒入杯中、加调料,但具体的冲泡和加调料方式不同。
不用模式的解决方案
实现简化版本
最直接的做法是为每种饮品写一个完整的制作方法:
public class Coffee {
public void make() {
System.out.println("烧水");
System.out.println("冲泡咖啡");
System.out.println("倒入杯中");
System.out.println("加糖和牛奶");
}
}
public class Tea {
public void make() {
System.out.println("烧水");
System.out.println("浸泡茶叶");
System.out.println("倒入杯中");
System.out.println("加柠檬");
}
}
使用示例
Coffee coffee = new Coffee();
coffee.make();
Tea tea = new Tea();
tea.make();
有何问题
- 代码重复,流程难以维护。
- 扩展新饮品需复制粘贴流程,易出错。
- 难以复用通用流程。
解决方案
模板方法模式的定义
定义一个操作中的算法骨架,将一些步骤延迟到子类中,使得子类可以不改变算法结构即可重定义该算法的某些特定步骤。
应用模板方法模式的思路
- 抽象父类定义模板方法,封装通用流程。
- 具体子类实现差异化步骤。
- 子类可选择性重写部分步骤。
模板方法模式的结构
- AbstractClass:抽象类,定义模板方法和基本步骤。
- ConcreteClassA/B:具体子类,实现差异化步骤。
模板方法模式的实现
// 抽象类
public abstract class Beverage {
// 模板方法
public final void make() {
boilWater();
brew();
pourInCup();
addCondiments();
}
private void boilWater() { System.out.println("烧水"); }
protected abstract void brew();
private void pourInCup() { System.out.println("倒入杯中"); }
protected abstract void addCondiments();
}
// 具体子类:咖啡
public class Coffee extends Beverage {
protected void brew() { System.out.println("冲泡咖啡"); }
protected void addCondiments() { System.out.println("加糖和牛奶"); }
}
// 具体子类:茶
public class Tea extends Beverage {
protected void brew() { System.out.println("浸泡茶叶"); }
protected void addCondiments() { System.out.println("加柠檬"); }
}
使用示例
public class Client {
public static void main(String[] args) {
Beverage coffee = new Coffee();
coffee.make();
Beverage tea = new Tea();
tea.make();
}
}
模板方法重写示例
示例结构
示例代码
见上文"模板方法模式的实现"部分。
模式讲解
模板方法模式的功能
- 复用通用流程,便于维护。
- 子类灵活扩展差异化步骤。
- 满足开闭原则。
实现成接口
- 抽象类定义模板方法和基本步骤。
使用工厂方法
- 可结合工厂方法模式,统一创建子类对象。
切换产品簇
- 可用于切换不同的流程模板,如不同饮品制作流程。