模板模式
模板模式(Template Pattern)是一种行为型设计模式,它定义了一个操作的算法骨架,将某些步骤的实现延迟到子类中。模板模式通过在抽象类中定义通用的算法结构,并允许子类重写特定步骤,从而实现代码复用和行为一致性。它常用于需要固定流程但部分步骤可自定义的场景。
模板模式的组成
模板模式通常包含以下几个角色:
- 抽象模板(Abstract Template):定义算法的骨架,包含模板方法(通常是
final
的)和需要子类实现的抽象方法。 - 具体模板(Concrete Template):继承抽象模板,实现抽象方法,定义具体步骤的行为。
- 客户端(Client):调用模板方法,执行算法流程。
工作原理
- 抽象模板类中定义了一个模板方法,描述了算法的整体流程,调用一系列步骤(包括抽象方法和具体方法)。
- 子类继承抽象模板类,实现抽象方法,提供具体步骤的实现。
- 客户端通过调用模板方法,触发整个算法流程,具体行为由子类决定。
UML 类图
┌────────────────────┐
│ AbstractTemplate │
├────────────────────┤
│ templateMethod() │
│ step1() │
│ step2() │
│ step3() │
└────────────────────┘
↑
│
┌────────────────────┐ ┌────────────────────┐
│ ConcreteTemplateA │ │ ConcreteTemplateB │
├────────────────────┤ ├────────────────────┤
│ step1() │ │ step1() │
│ step2() │ │ step2() │
└────────────────────┘ └────────────────────┘
代码示例(以 Java 为例)
以下是一个模板模式的实现,模拟不同类型饮料的制作流程:
// 抽象模板类
abstract class BeverageMaker {
// 模板方法,定义饮料制作流程
final void prepareBeverage() {
boilWater();
brew();
pourInCup();
addCondiments();
}
// 固定步骤
void boilWater() {
System.out.println("烧开水");
}
void pourInCup() {
System.out.println("倒入杯子");
}
// 抽象步骤,由子类实现
abstract void brew();
abstract void addCondiments();
}
// 具体模板类:咖啡
class CoffeeMaker extends BeverageMaker {
@Override
void brew() {
System.out.println(“冲泡咖啡”);
}
@Override
void addCondiments() {
System.out.println("添加糖和奶");
}
}
// 具体模板类:茶
class TeaMaker extends BeverageMaker {
@Override
void brew() {
System.out.println(“浸泡茶叶”);
}
@Override
void addCondiments() {
System.out.println("添加柠檬");
}
}
// 测试代码
public class TemplatePatternExample {
public static void main(String[] args) {
System.out.println(“制作咖啡:”);
BeverageMaker coffee = new CoffeeMaker();
coffee.prepareBeverage();
System.out.println("\n制作茶:");
BeverageMaker tea = new TeaMaker();
tea.prepareBeverage();
}
}
输出:
制作咖啡:
烧开水
冲泡咖啡
倒入杯子
添加糖和奶
制作茶:
烧开水
浸泡茶叶
倒入杯子
添加柠檬
模板模式的特点
- 优点:
- 封装不变的算法骨架,复用公共代码,符合代码复用原则。
- 子类只需实现特定步骤,降低开发复杂性。
- 模板方法通常为
final
,确保算法流程不可更改,增强一致性。 - 符合开闭原则,新增行为只需添加新的子类。
- 缺点:
- 每个具体实现都需要一个子类,如果变化较多,可能导致类数量增加。
- 抽象模板类的设计需要仔细规划,抽象方法过多或过少都会影响灵活性。
使用场景
- 当需要定义一个固定的算法流程,但部分步骤需要子类自定义时:
- 数据处理流程(如文件解析、数据导出)。
- 游戏中的关卡加载流程(如初始化、加载资源、渲染)。
- 业务流程(如订单处理、支付流程)。
- 需要统一行为框架但允许具体实现差异的场景:
- 不同类型的报表生成。
- 不同协议的网络通信处理。
- 希望通过复用公共代码减少重复开发的场景。
注意事项
- 模板方法的控制:模板方法通常声明为
final
,防止子类修改算法骨架。 - 钩子方法:可以在抽象模板类中提供空实现或默认实现的方法(称为钩子方法),让子类选择是否覆盖。
- 与策略模式的区别:
- 模板模式通过继承定义算法骨架,强调固定流程。
- 策略模式通过组合动态选择算法,强调行为的可替换性。
- 扩展性:设计抽象模板时,应尽量将变化点抽象为方法,方便子类扩展。
总结
模板模式通过在抽象类中定义算法骨架,将可变部分延迟到子类实现,实现了代码复用和行为一致性。它适用于固定流程但细节可变的场景,如流程控制、业务处理等。设计时需平衡抽象方法的粒度和数量,以确保系统的灵活性和可维护性。