Java模板方法模式源码剖析及使用场景

一、原理与通俗理解

模板方法模式定义了一个算法的骨架,将某些步骤推迟到子类中实现。模板方法定义一个算法的骨架,将一些步骤的实现延迟到子类中完成。这样做的目的是确保算法的结构保持不变,同时又可以为不同的子类提供特定步骤的实现。

比如去餐馆吃饭,餐馆有固定的流程(下单->上菜->吃饭->付款),这就是模板方法。但对于不同的顾客,他们点的菜不同(重写了上菜这一步骤)。

二、案例演示

  1. 员工审核系统需求
    1. 收集员工信息
    2. 验证员工资格
    3. 核心决策是否雇佣
    4. 雇佣或拒绝员工
// 抽象类 - 模板方法
abstract class EmployeeApprover {
    // 模板方法
    public final void processRequest(EmployeeRequest request) {
        collectEmployeeInfo(request); // 1
        verifyEmployeeInfo(request); // 2
        if (approveEmployee(request)) { // 3
            hireEmployee(request); // 4
        } else {
            rejectEmployee(request); // 4
        }
    }

    // 收集员工信息 - 由子类实现
    protected abstract void collectEmployeeInfo(EmployeeRequest request);

    // 验证员工资格 - 由子类实现
    protected abstract void verifyEmployeeInfo(EmployeeRequest request);

    // 核心决策 - 由子类实现
    protected abstract boolean approveEmployee(EmployeeRequest request);

    // 具体雇佣步骤
    private void hireEmployee(EmployeeRequest request) {
        System.out.println("已雇佣员工: " + request.getName());
    }

    // 具体拒绝步骤
    private void rejectEmployee(EmployeeRequest request) {
        System.out.println("已拒绝员工: " + request.getName());
    }
}

// 具体子类 - 实现抽象方法
class ITEmployeeApprover extends EmployeeApprover {
    @Override
    protected void collectEmployeeInfo(EmployeeRequest request) {
        // 收集IT员工信息
    }

    @Override
    protected void verifyEmployeeInfo(EmployeeRequest request) {
        // 验证IT员工资格
    }

    @Override
    protected boolean approveEmployee(EmployeeRequest request) {
        // 审核IT员工是否合格
        return true;
    }
}
  1. CRM系统订单处理需求
    1. 收集订单信息
    2. 验证订单信息
    3. 核心决策是否发货
    4. 发货或拒绝订单
// 抽象类 - 模板方法
abstract class OrderProcessor {
    // 模板方法
    public final void processOrder(Order order) {
        collectOrderInfo(order); // 1
        verifyOrderInfo(order); // 2
        if (approveOrder(order)) { // 3
            shipOrder(order); // 4
        } else {
            rejectOrder(order); // 4
        }
    }

    // 收集订单信息 - 由子类实现
    protected abstract void collectOrderInfo(Order order);

    // 验证订单信息 - 由子类实现
    protected abstract void verifyOrderInfo(Order order);

    // 核心决策 - 由子类实现 
    protected abstract boolean approveOrder(Order order);

    // 具体发货步骤
    private void shipOrder(Order order) {
        System.out.println("已发货订单: " + order.getId());
    }

    // 具体拒绝步骤
    private void rejectOrder(Order order) {
        System.out.println("已拒绝订单: " + order.getId());
    }
}

// 具体子类 - 实现抽象方法
class OnlineOrderProcessor extends OrderProcessor {
    @Override
    protected void collectOrderInfo(Order order) {
        // 收集在线订单信息
    }

    @Override
    protected void verifyOrderInfo(Order order) {
        // 验证在线订单信息
    }

    @Override
    protected boolean approveOrder(Order order) {
        // 审核在线订单是否合格
        return true;
    }
}

三、Java源码中的模板方法模式

  1. InputStream抽象类

InputStream定义了读取数据的标准方法read(),而具体的读取方式由子类实现。

public abstract class InputStream implements Closeable {
    public abstract int read() throws IOException;
    
    public int read(byte b[]) throws IOException {
        return read(b, 0, b.length);
    }
    
    public int read(byte b[], int off, int len) throws IOException {
        // 模板方法
    }
    
    // 其他方法...
}
  1. AbstractList抽象类

AbstractList提供了模板方法addAll()用于批量添加元素,而具体的添加逻辑由子类实现。

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    public boolean addAll(Collection<? extends E> c) {
        // 模板方法
        return batchOperation(c, true);
    }
    
    private boolean batchOperation(...) {
        // ...
        for (E e : c)
            result = add(e); // 调用抽象方法
    }

    public abstract boolean add(E e); // 抽象方法,子类实现
}
  1. Spring JdbcTemplate

JdbcTemplate使用模板方法模式对底层的JDBC操作进行封装,开发者只需实现回调接口即可。以query方法为例:

public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {  

    public <T> T query(String sql, Object[] args, ResultSetExtractor<T> rse) throws DataAccessException {
        // 模板方法
        return query(sql, newArgPreparedStatementSetter(args), rse);
    }

    // 实际的查询逻辑
    private <T> T query(PreparedStatementCreator psc, ResultSetExtractor<T> rse) throws DataAccessException {
        // 具体的数据库操作...
        rse.extractData(rs); // 调用回调接口
    }
}

四、总结优缺点以及使用经验

优点:

  1. 封装不变部分,扩展可变部分,代码复用性好
  2. 父类调用子类操作,通过子类扩展增强功能
  3. 符合开闭原则和里氏替换原则

缺点:

  1. 每个不同的实现都需要定义一个子类,类的个数可能过多
  2. 父类和子类之间存在潜在的扩展性限制
  3. 编写过程复杂,逻辑较难理解

使用经验:

  1. 适用于复杂流程,有固定不变的算法骨架和某些可变的细节
  2. 需要先分清楚算法固定部分和可变部分
  3. 体现了模板模式的核心思想"继承 + 多态"
  4. 在框架设计中是常用的模式,可以提高代码的复用性
  5. 不建议过度使用,需要权衡利弊,避免类膨胀

模板方法模式是一种典型的通过交换算法步骤扩展功能的设计模式,适用于算法骨架固定,某些步骤需要不同实现的场景。恰当使用可以提高代码复用性和系统扩展性。

  • 13
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java语录精选

你的鼓励是我坚持下去的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值