当前位置: 首页 > news >正文

Java模板方法模式详解

模板方法模式详解

一、模式定义

模板方法模式(Template Method Pattern)定义一个操作中的算法骨架,将某些步骤延迟到子类实现。

二、核心结构

1. 抽象模板类

public abstract class AbstractTemplate {
    // 模板方法(final防止子类覆盖)
    public final void templateMethod() {
        step1();
        step2();
        step3();
        if(hook()) {
            step4();
        }
    }
    
    // 抽象方法(必须由子类实现)
    protected abstract void step2();
    
    // 具体方法(已有默认实现)
    protected void step1() {
        System.out.println("执行步骤1");
    }
    
    protected void step3() {
        System.out.println("执行步骤3");
    }
    
    // 钩子方法(可选覆盖)
    protected boolean hook() {
        return true;
    }
    
    protected void step4() {
        System.out.println("执行步骤4");
    }
}

2. 具体实现类

public class ConcreteClassA extends AbstractTemplate {
    protected void step2() {
        System.out.println("A实现-步骤2");
    }
    
    protected boolean hook() {
        return false; // 关闭步骤4
    }
}

public class ConcreteClassB extends AbstractTemplate {
    protected void step2() {
        System.out.println("B实现-步骤2");
    }
    
    protected void step4() {
        System.out.println("B定制-步骤4");
    }
}

三、完整示例:饮料制作系统

1. 抽象饮料类

public abstract class BeverageTemplate {
    // 模板方法(final)
    public final void prepareBeverage() {
        boilWater();
        brew();
        pourInCup();
        if(customerWantsCondiments()) {
            addCondiments();
        }
    }
    
    protected abstract void brew();
    
    protected abstract void addCondiments();
    
    protected void boilWater() {
        System.out.println("煮沸水");
    }
    
    protected void pourInCup() {
        System.out.println("倒入杯中");
    }
    
    // 钩子方法
    protected boolean customerWantsCondiments() {
        return true;
    }
}

2. 具体饮料实现

// 咖啡
public class Coffee extends BeverageTemplate {
    protected void brew() {
        System.out.println("冲泡咖啡粉");
    }
    
    protected void addCondiments() {
        System.out.println("加糖和牛奶");
    }
    
    protected boolean customerWantsCondiments() {
        String answer = getUserInput();
        return answer.toLowerCase().startsWith("y");
    }
    
    private String getUserInput() {
        System.out.print("要加糖和牛奶吗(y/n)? ");
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        try {
            return reader.readLine();
        } catch (IOException e) {
            return "no";
        }
    }
}

// 茶
public class Tea extends BeverageTemplate {
    protected void brew() {
        System.out.println("浸泡茶叶");
    }
    
    protected void addCondiments() {
        System.out.println("加柠檬");
    }
}

3. 客户端使用

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

四、高级应用:数据库操作模板

1. 抽象DAO模板

public abstract class JdbcTemplate {
    // 模板方法
    public final <T> T execute(String sql, RowMapper<T> rowMapper) {
        Connection conn = null;
        PreparedStatement stmt = null;
        ResultSet rs = null;
        try {
            conn = getConnection();
            stmt = conn.prepareStatement(sql);
            setParameters(stmt);
            rs = stmt.executeQuery();
            return rowMapper.mapRow(rs);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            closeResources(conn, stmt, rs);
        }
    }
    
    protected abstract void setParameters(PreparedStatement stmt) throws SQLException;
    
    protected Connection getConnection() throws SQLException {
        return DriverManager.getConnection("jdbc:mysql://localhost:3306/test");
    }
    
    protected void closeResources(Connection conn, Statement stmt, ResultSet rs) {
        try { if (rs != null) rs.close(); } catch (SQLException e) {}
        try { if (stmt != null) stmt.close(); } catch (SQLException e) {}
        try { if (conn != null) conn.close(); } catch (SQLException e) {}
    }
}

2. 行映射接口

public interface RowMapper<T> {
    T mapRow(ResultSet rs) throws SQLException;
}

3. 具体DAO实现

public class UserDao extends JdbcTemplate {
    public User findById(long id) {
        return execute("SELECT * FROM users WHERE id = ?", rs -> {
            User user = new User();
            user.setId(rs.getLong("id"));
            user.setName(rs.getString("name"));
            return user;
        });
    }
    
    protected void setParameters(PreparedStatement stmt) throws SQLException {
        stmt.setLong(1, 1L); // 设置查询参数
    }
}

五、模式优势

  1. 提高代码复用性
  2. 实现反向控制(好莱坞原则)
  3. 便于扩展和维护
  4. 符合开闭原则

六、适用场景

  1. 多个类有相同算法结构
  2. 需要控制子类扩展点
  3. 存在公共行为需要抽取
  4. 框架设计中的流程控制

七、注意事项

  1. 模板方法应该声明为final
  2. 合理设计抽象方法和钩子方法
  3. 避免过度抽象导致复杂度增加
  4. 与策略模式区分使用场景

八、最佳实践

  1. 使用钩子方法提供灵活扩展点
  2. 保持模板方法简洁
  3. 合理命名抽象方法
  4. 考虑与工厂方法模式结合使用
  5. 为常用操作提供默认实现

九、完整示例代码结构

src/
├── main/
│ ├── java/
│ │ ├── template/
│ │ │ ├── AbstractTemplate.java
│ │ │ ├── ConcreteClassA.java
│ │ │ ├── ConcreteClassB.java
│ │ │ ├── BeverageTemplate.java
│ │ │ ├── Coffee.java
│ │ │ ├── Tea.java
│ │ │ ├── JdbcTemplate.java
│ │ │ ├── UserDao.java
│ │ │ └── BeverageTest.java
http://www.dtcms.com/a/112181.html

相关文章:

  • Ansible Playbook 进阶探秘:Handlers、变量、循环及条件判断全解析
  • 【设计模式】原型模式:用“克隆”术让对象创建更灵活
  • 开放最短路径优先 - OSPF【LSA详细】
  • 政安晨【超级AI工作流】—— 基于COZE探索有趣的主题互动问答工作流(同宇宙儿童提问机)
  • AI 数理逻辑基础之统计学基本原理(上)
  • 【3】数据结构的双向链表章
  • 每日一题洛谷P8649 [蓝桥杯 2017 省 B] k 倍区间c++
  • 【嵌入式-stm32电位器控制以及旋转编码器控制LED亮暗】
  • DHCP协议和win server2022无脑配置DHCP
  • 残差神经网络(ResNet)概念解析与用法实例:简洁的图像处理任务
  • 树莓派5使用问题
  • Mysql 使用时的一些规范值
  • Kibana 连接 Elasticsearch(8.11.3)教程
  • Vue组件化开发深度解析:Element UI与Ant Design Vue对比实践
  • WEB安全--提权思路
  • LeetCode 1817 查找用户活跃分钟数
  • Linux下调试器gdb_cgdb使用
  • 中小企业数字化赋能专项行动:Websoft9 开源聚合平台的明确行动计划
  • 蓝桥杯真题———交换瓶子
  • 【嵌入式】——Linux系统调用编程
  • Appium 自动化测试从入门到精通
  • 我与数学建模之波折
  • One API:LLM API 管理 分发系统,github 24.2K Star!
  • 算法设计与分析5(动态规划)
  • Go+Gin实现多文件上传
  • Linux: 系统内核中的信号
  • 【NLP 53、投机采样加速推理】
  • 【CMake】《CMake构建实战:项目开发卷》笔记-Chapter8-生成器表达式
  • LIO-SAM跑自己的数据集
  • 局域网:电脑或移动设备作为主机实现局域网访问