【设计模式精讲 Day 22】模板方法模式(Template Method Pattern)
文章标签
设计模式, 模板方法模式, Java开发, 面向对象设计, 软件架构, 设计模式实战, Java应用开发
文章简述
模板方法模式是一种行为型设计模式,它通过定义一个算法的骨架,并将某些步骤延迟到子类中实现。这种模式允许子类在不改变算法结构的前提下,重新定义算法的某些步骤,从而提高代码复用性和可扩展性。本文作为"设计模式精讲"系列的第22天,深入讲解了模板方法模式的核心思想、实现方式和实际应用场景。文章通过完整的Java代码示例,展示了如何在具体业务场景中使用模板方法模式优化系统结构,并结合真实案例分析其优势与局限性。无论你是初学者还是有经验的开发者,这篇文章都将帮助你掌握模板方法模式的设计精髓并应用于实际项目中。
【设计模式精讲 Day 22】模板方法模式(Template Method Pattern)
开篇:模板方法模式的核心思想与应用价值
今天是"设计模式精讲"系列的第22天,我们聚焦于模板方法模式(Template Method Pattern)。模板方法模式是一种行为型设计模式,它通过定义一个算法的骨架,并将某些步骤延迟到子类中实现,使得子类可以在不改变算法结构的前提下,重新定义算法的某些步骤。
在软件开发中,很多业务流程具有固定的执行顺序,但其中某些步骤可能因具体需求而变化。例如,支付流程通常包括验证、扣款、记录日志等步骤,但不同支付方式的具体实现可能不同。如果直接在同一个类中处理这些逻辑,会导致代码重复和难以维护。而模板方法模式通过将公共逻辑封装在父类中,将可变部分交给子类实现,实现了算法结构与具体实现的解耦。
本篇文章将从模式定义、结构、适用场景、实现方式、工作原理、优缺点分析、案例分析等多个维度,全面解析模板方法模式,并提供完整可运行的Java代码示例,帮助你真正掌握这一设计模式。
模式定义
1.1 正式定义
模板方法模式(Template Method Pattern)是一种行为型设计模式,它定义了一个算法的框架,并在该框架中调用一些抽象方法或钩子方法,由子类来实现这些方法。这样,算法的结构保持不变,但具体的实现可以由不同的子类进行定制。
1.2 核心思想
- 算法骨架固定:算法的整体流程由父类定义。
- 具体步骤延迟实现:部分步骤由子类实现,增强灵活性。
- 复用性高:避免重复代码,提升代码复用性。
- 符合开闭原则:对扩展开放,对修改关闭。
模式结构
2.1 UML 类图说明(文字描述)
模板方法模式包含以下几个关键角色:
角色 | 说明 |
---|---|
AbstractClass(抽象类) | 定义算法的骨架,包含模板方法和抽象方法。 |
ConcreteClass(具体类) | 实现抽象方法,完成算法的具体步骤。 |
2.2 示例结构说明
AbstractClass
中定义了一个templateMethod()
方法,该方法调用了多个抽象方法(如primitiveOperation1()
、primitiveOperation2()
等)。ConcreteClassA
和ConcreteClassB
分别实现这些抽象方法,提供不同的具体逻辑。
适用场景
场景 | 说明 |
---|---|
多个类有相似的算法流程 | 当多个类需要按照相同流程执行操作时,适合使用模板方法模式。 |
算法的某些步骤可能变化 | 如果算法中的某些步骤需要根据情况变化,适合将其封装为抽象方法。 |
提高代码复用性 | 将公共逻辑放在父类中,减少重复代码。 |
控制算法的执行顺序 | 保证算法的执行顺序一致,同时允许子类自定义部分步骤。 |
实现方式
3.1 Java 代码实现
以下是一个基于模板方法模式的简单示例,模拟一个"咖啡与茶的制作流程"。
3.1.1 抽象类
java
// Beverage.java
public abstract class Beverage {
// 模板方法:定义算法的骨架
public final void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}
// 具体方法:所有子类共有的步骤
private void boilWater() {
System.out.println("煮水");
}
private void pourInCup() {
System.out.println("倒入杯子");
}
// 抽象方法:子类需要实现的方法
protected abstract void brew();
// 钩子方法:可选实现
protected boolean isCondimentRequired() {
return true;
}
// 子类可以选择是否重写此方法
protected void addCondiments() {
if (isCondimentRequired()) {
System.out.println("添加配料");
}
}
}
3.1.2 具体类
java
// Coffee.java
public class Coffee extends Beverage {
@Override
protected void brew() {
System.out.println("冲泡咖啡");
}
@Override
protected boolean isCondimentRequired() {
return true; // 咖啡需要加糖
}
}
// Tea.java
public class Tea extends Beverage {
@Override
protected void brew() {
System.out.println("冲泡茶叶");
}
@Override
protected boolean isCondimentRequired() {
return false; // 茶不需要加糖
}
}
3.1.3 测试类
java
// TemplateMethodPatternTest.java
public class TemplateMethodPatternTest {
public static void main(String[] args) {
Beverage coffee = new Coffee();
coffee.prepareRecipe();
System.out.println("-----------");
Beverage tea = new Tea();
tea.prepareRecipe();
}
}
输出:
煮水
冲泡咖啡
倒入杯子
添加配料
-----------
煮水
冲泡茶叶
倒入杯子
工作原理
模板方法模式通过将算法的通用逻辑封装在父类中,而将特定逻辑交由子类实现,从而实现算法结构与具体实现的分离。
- 模板方法:定义算法的步骤,调用抽象方法或钩子方法。
- 抽象方法:由子类实现,提供具体逻辑。
- 钩子方法:提供默认实现,子类可以选择是否覆盖。
这种机制符合开闭原则 ,即对扩展开放,对修改关闭。同时,也符合单一职责原则,每个类只关注自己的职责。
优缺点分析
优点 | 缺点 |
---|---|
代码复用性强:公共逻辑集中管理,避免重复代码。 | 增加类的数量:每个子类都需要继承抽象类。 |
提高可维护性:算法结构清晰,便于后期维护和扩展。 | 灵活性有限:如果算法结构频繁变化,可能需要重构。 |
符合开闭原则:新增功能只需扩展子类,无需修改现有代码。 | 过度依赖继承:可能导致类层次复杂。 |
案例分析:电商订单处理流程中的模板方法模式应用
4.1 问题描述
某电商平台的订单处理流程包括:校验订单、计算价格、生成发票、发送通知等步骤。不同类型的订单(如普通订单、促销订单、预售订单)在某些步骤上存在差异,如促销订单需要额外的折扣计算,预售订单需要库存预扣。
4.2 解决方案
采用模板方法模式重构订单处理流程,将通用逻辑放在父类中,将可变部分交给子类实现。
4.2.1 抽象类
java
// OrderProcessor.java
public abstract class OrderProcessor {
// 模板方法
public final void processOrder(Order order) {
validate(order);
calculatePrice(order);
generateInvoice(order);
sendNotification(order);
}
protected abstract void validate(Order order);
protected abstract void calculatePrice(Order order);
protected void generateInvoice(Order order) {
System.out.println("生成发票");
}
protected void sendNotification(Order order) {
System.out.println("发送通知");
}
}
4.2.2 具体类
java
// NormalOrderProcessor.java
public class NormalOrderProcessor extends OrderProcessor {
@Override
protected void validate(Order order) {
System.out.println("验证普通订单");
}
@Override
protected void calculatePrice(Order order) {
System.out.println("计算普通订单价格");
}
}
// PromotionOrderProcessor.java
public class PromotionOrderProcessor extends OrderProcessor {
@Override
protected void validate(Order order) {
System.out.println("验证促销订单");
}
@Override
protected void calculatePrice(Order order) {
System.out.println("计算促销订单价格(含折扣)");
}
}
4.2.3 使用示例
java
public class OrderProcessorTest {
public static void main(String[] args) {
Order order = new Order();
OrderProcessor normalProcessor = new NormalOrderProcessor();
normalProcessor.processOrder(order);
System.out.println("----------");
OrderProcessor promotionProcessor = new PromotionOrderProcessor();
promotionProcessor.processOrder(order);
}
}
输出:
验证普通订单
计算普通订单价格
生成发票
发送通知
----------
验证促销订单
计算促销订单价格(含折扣)
生成发票
发送通知
与其他模式的关系
模式 | 关系 | 说明 |
---|---|---|
策略模式(Strategy Pattern) | 相似但用途不同 | 策略模式封装算法,模板方法模式封装算法骨架 |
工厂模式(Factory Pattern) | 可组合使用 | 工厂模式用于创建对象,模板方法模式用于定义算法结构 |
命令模式(Command Pattern) | 不同但可结合使用 | 命令模式封装请求,模板方法模式控制算法流程 |
总结
5.1 本日学习要点
- 模板方法模式的核心思想是将算法的骨架定义在父类中,将具体步骤延迟到子类中实现。
- 通过模板方法,可以统一算法的执行流程,同时允许子类灵活调整部分步骤。
- 模板方法模式适用于具有固定流程但部分步骤需定制的场景。
- 通过完整 Java 示例,展示了模板方法模式的实现方式和实际应用。
- 模板方法模式与策略模式、工厂模式等存在相似之处,但在应用场景上有明显区别。
5.2 下一日预告
明天我们将进入"设计模式精讲"系列的第23天,主题为【设计模式精讲 Day 23】访问者模式(Visitor Pattern)。我们将探讨如何通过访问者模式实现对对象结构的遍历与操作,提升系统的灵活性和可扩展性。敬请期待!
进一步学习资料
- 《设计模式:可复用面向对象软件的基础》 ------ GoF 经典著作
- 模板方法模式 - Wikipedia
- Java 设计模式之模板方法模式详解
- Spring 框架中的模板方法模式应用
- 模板方法模式 vs 策略模式对比
【设计模式精讲 Day 22】模板方法模式(Template Method Pattern) 已完成,欢迎转发、收藏、评论交流。