Java模板模式案例如何编写

wen java案例 27

Java模板模式案例如何编写:从理论到实战的完整指南

目录导读

  1. 模板模式是什么?为什么你需要它?
  2. 模板模式的核心结构与UML图解
  3. 一个完整的Java模板模式案例(含代码)
  4. 案例详解:从咖啡到茶的制作流程模拟
  5. 模板模式在Spring框架中的真实应用
  6. 常见问题与最佳实践(含问答)
  7. 何时选用模板模式?

模板模式是什么?为什么你需要它?

问:模板模式(Template Method Pattern)是什么? 答:模板模式是一种行为型设计模式,它在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中实现,模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些特定步骤。

Java模板模式案例如何编写

问:为什么Java开发中经常使用模板模式? 答:因为它能有效消除重复代码,提高复用性,例如在Web开发、批处理、数据访问层中,当多个业务流程拥有相似的步骤但细节不同时,模板模式可以让你把通用流程固定下来,让子类只关心变化的部分。

核心思想:父类定义“做什么”,子类定义“怎么做”,父类中的模板方法通常被声明为final,防止子类修改整个流程。


模板模式的核心结构与UML图解

模板模式主要由以下角色组成:

角色 名称 职责
抽象类(AbstractClass) 定义模板方法,包含一个或多个抽象操作/钩子方法 定义算法骨架
具体子类(ConcreteClass) 实现抽象类中的抽象方法 完成特定步骤

UML简示

AbstractClass
├── templateMethod() ← final,不可重写
│   ├── stepOne() ← 抽象方法
│   ├── stepTwo() ← 具体方法(默认实现)
│   ├── hookMethod() ← 钩子方法(可选覆盖)
│   └── stepThree() ← 抽象方法
ConcreteClassA → 实现stepOne()、stepThree()
ConcreteClassB → 实现stepOne()、stepThree(),并覆盖hookMethod()

关键点

  • 模板方法(templateMethod())用final修饰,确保算法结构不变。
  • 抽象方法由子类强制实现。
  • 钩子方法(Hook)提供默认空实现,子类可选择是否覆盖。

一个完整的Java模板模式案例(含代码)

案例背景:饮料制作流程

我们模拟两种饮料:咖啡和茶,它们的制作步骤非常相似:

  1. 烧水
  2. 冲泡饮品
  3. 倒入杯子
  4. 添加调料

其中步骤1和3完全相同,步骤2和4因饮料不同而异。

代码实现

第一步:定义抽象类 Beverage

public abstract class Beverage {
    // 模板方法,声明为final防止子类修改流程
    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 abstract void addCondiments();
}

第二步:创建具体子类 Coffee

public class Coffee extends Beverage {
    @Override
    protected void brew() {
        System.out.println("用沸水冲泡咖啡粉");
    }
    @Override
    protected void addCondiments() {
        System.out.println("加入糖和牛奶");
    }
}

第三步:创建具体子类 Tea

public class Tea extends Beverage {
    @Override
    protected void brew() {
        System.out.println("用热水浸泡茶叶");
    }
    @Override
    protected void addCondiments() {
        System.out.println("加入柠檬片");
    }
}

第四步:客户端测试

public class TemplatePatternDemo {
    public static void main(String[] args) {
        Beverage coffee = new Coffee();
        Beverage tea = new Tea();
        System.out.println("===== 制作咖啡 =====");
        coffee.prepareRecipe();
        System.out.println("\n===== 制作茶 =====");
        tea.prepareRecipe();
    }
}

输出结果

===== 制作咖啡 =====
烧开水
用沸水冲泡咖啡粉
将饮品倒入杯子
加入糖和牛奶
===== 制作茶 =====
烧开水
用热水浸泡茶叶
将饮品倒入杯子
加入柠檬片

案例详解:从咖啡到茶的制作流程模拟

模板方法的执行流程

  1. 父类Beverage.prepareRecipe()定义不可变的算法顺序。
  2. 子类CoffeeTea各自实现brew()addCondiments()
  3. 客户端无需关心具体步骤,直接调用prepareRecipe()即可完成完整流程。

如何扩展这个案例?

假设你希望某些饮料不需要加调料(如白开水),可以在父类中添加一个钩子方法

// 在父类中添加钩子方法
protected boolean customerWantsCondiments() {
    return true; // 默认需要
}

然后在模板方法中条件判断:

public final void prepareRecipe() {
    boilWater();
    brew();
    pourInCup();
    if (customerWantsCondiments()) {
        addCondiments();
    }
}

子类可以重写钩子方法:

public class PlainWater extends Beverage {
    @Override
    protected void brew() {
        // 空白实现,实际就是白开水
    }
    @Override
    protected boolean customerWantsCondiments() {
        return false;
    }
}

问:钩子方法有什么作用? 答:钩子方法允许子类在不破坏模板方法结构的前提下,控制算法的某些部分是否执行,它是模板模式的“可选项控制开关”。


模板模式在Spring框架中的真实应用

JdbcTemplate 与数据库操作

Spring的JdbcTemplate是模板模式的经典实现,它定义了“获取连接-执行SQL-处理结果-关闭资源”的固定流程,而开发者只需通过回调接口提供SQL语句和结果映射逻辑:

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.query("SELECT * FROM users", new RowMapper<User>() {
    public User mapRow(ResultSet rs, int rowNum) throws SQLException {
        User user = new User();
        user.setId(rs.getInt("id"));
        user.setName(rs.getString("name"));
        return user;
    }
});

HttpServletservice()方法

Java Servlet中的HttpServlet类提供了doGet()doPost()等钩子方法,而service()方法作为模板方法,根据HTTP请求类型调用对应的方法。

在框架源码中的其他案例

  • Spring的AbstractApplicationContext定义了Bean容器的刷新流程。
  • MyBatis的BaseExecutor定义了查询执行的骨架。

常见问题与最佳实践(含问答)

问1:模板模式和策略模式有什么区别? 答:模板模式关注算法结构的复用,通过继承复用相同步骤;策略模式关注算法行为的变换,通过组合实现不同算法,简单说:模板模式是“同一个算法的不同步骤实现”,策略模式是“不同算法的替换”。

问2:模板模式会导致类爆炸吗? 答:如果每一个变化步骤都创建一个新子类,确实可能导致子类过多,建议配合工厂模式或组合模式,或者在子类中通过参数化来控制差异。

问3:什么时候应该避免使用模板模式? 答:当算法步骤数量非常少且稳定时,使用简单继承即可,当算法步骤未来可能频繁增加或减少时,模板模式的“骨架固定性”反而会成为约束。

最佳实践建议

  1. 模板方法尽量声明为final,避免子类意外重写。
  2. 抽象方法定义为protected,仅对子类暴露。
  3. 钩子方法使用protected和空实现(或默认true),子类按需覆盖。
  4. 不要在模板方法中添加if-else判断具体类型,这违背了开闭原则。

何时选用模板模式?

  • 多个类拥有相似的算法骨架,但部分步骤实现不同。
  • 需要控制子类的扩展点,防止子类随意修改流程。
  • 代码重构时,抽取出公共部分,减少重复。

一句话总结:模板模式就像一张“行车路线图”——路线固定,但途中停车点(具体操作)你可以自己规划,掌握它,能让你的Java代码更优雅、更易维护。


本文参考了《Head First 设计模式》、Spring源码官方文档以及多个Java社区的技术分享,经融会贯通后形成此实战指南。

抱歉,评论功能暂时关闭!