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

【设计模式】模板模式

简介
假设你要冲泡咖啡和茶,两者的流程相似但部分步骤不同:

  1. 烧水(公共步骤)
  2. 加入主材料(咖啡粉/茶叶)
  3. 添加调料(糖/牛奶)→ 可选步骤
  4. 倒进杯子(公共步骤)

模板模式的作用

  • 在父类中定义冲泡饮料的固定流程(如烧水、倒杯),子类只需实现差异步骤(如加咖啡粉或茶叶)。
  • 避免重复代码,同时允许灵活扩展(如是否加调料)。

适用场景

  • 多个类有相同流程,但某些步骤实现不同(如数据处理、文件解析)。
  • 需要控制子类的扩展点(如钩子方法)。

优点

  • 代码复用:公共逻辑在父类实现。
  • 灵活扩展:子类只需关注差异步骤。

缺点

  • 父类定义流程,子类可能被限制灵活性。
  • 容易因父类修改影响所有子类。

代码
// 抽象模板类:定义饮料冲泡流程
abstract class BeverageTemplate {
    // 模板方法(final 防止子类覆盖)
    public final void prepareBeverage() {
        boilWater();
        brew();
        addCondiments(); // 钩子方法(可选步骤)
        pourInCup();
    }

    // 公共步骤
    private void boilWater() {
        System.out.println("烧水");
    }

    private void pourInCup() {
        System.out.println("倒进杯子");
    }

    // 抽象方法:子类必须实现
    protected abstract void brew();

    // 钩子方法(默认不添加调料,子类可选覆盖)
    protected void addCondiments() {}
}

// 具体子类:咖啡
class Coffee extends BeverageTemplate {
    protected void brew() {
        System.out.println("加入咖啡粉");
    }

    @Override
    protected void addCondiments() {
        System.out.println("加糖和牛奶");
    }
}

// 具体子类:茶
class Tea extends BeverageTemplate {
    protected void brew() {
        System.out.println("加入茶叶");
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        BeverageTemplate coffee = new Coffee();
        coffee.prepareBeverage();
        // 输出:
        // 烧水 → 加入咖啡粉 → 加糖和牛奶 → 倒进杯子

        BeverageTemplate tea = new Tea();
        tea.prepareBeverage();
        // 输出:
        // 烧水 → 加入茶叶 → 倒进杯子
    }
}
类图

在这里插入图片描述

@startuml
abstract class BeverageTemplate {
    + prepareBeverage(): void
    - boilWater(): void
    - pourInCup(): void
    # brew(): void
    # addCondiments(): void
}

class Coffee {
    # brew(): void
    # addCondiments(): void
}

class Tea {
    # brew(): void
}

BeverageTemplate <|-- Coffee
BeverageTemplate <|-- Tea
@enduml

场景
数据库连接、执行SQL、关闭连接的固定流程。

// 抽象模板类
public abstract class JdbcTemplate {
    // 模板方法
    public final void execute() {
        connect();
        String sql = buildSql(); // 抽象方法
        executeSql(sql);
        close();
    }

    private void connect() {
        System.out.println("连接数据库");
    }

    private void executeSql(String sql) {
        System.out.println("执行SQL: " + sql);
    }

    private void close() {
        System.out.println("关闭连接");
    }

    protected abstract String buildSql();
}

// 具体子类:用户查询
class UserQuery extends JdbcTemplate {
    protected String buildSql() {
        return "SELECT * FROM users";
    }
}

// 具体子类:订单插入
class OrderInsert extends JdbcTemplate {
    protected String buildSql() {
        return "INSERT INTO orders VALUES (...)";
    }
}

// 客户端代码
public class DatabaseClient {
    public static void main(String[] args) {
        JdbcTemplate userQuery = new UserQuery();
        userQuery.execute();
        // 输出:
        // 连接数据库 → 执行SQL: SELECT * FROM users → 关闭连接

        JdbcTemplate orderInsert = new OrderInsert();
        orderInsert.execute();
        // 输出:
        // 连接数据库 → 执行SQL: INSERT INTO orders... → 关闭连接
    }
}

相关文章:

  • LeetCode详解之如何一步步优化到最佳解法:26. 删除有序数组中的重复项
  • 解决leetcode第3510题移除最小数对使数组有序II
  • Flutter性能优化终极指南:从JIT到AOT的深度调优
  • 视频孪生赋能交警构建“空地一体“智慧交管体系的创新实践
  • leetcode797图论-对邻接矩阵和邻接表不同形式进行dfs与bfs遍历方法
  • 【C++差分数组 树上倍增】P6869 [COCI2019-2020#5] Putovanje|普及+
  • 电影舆情分析可视化平台管理端实现
  • Redisson的RedLock与联锁(MultiLock)的区别
  • 手持式RFID读写器对比固定式读写器的差异优势
  • Mathwork Platform - Matlab Help Center - Concept and Application
  • 前端面试宝典---数据类型
  • Redis基础指令(Windows)
  • 每日一题——AB10 反转链表
  • 电子电气架构 --- 新能源汽车电子电气系统功能需求
  • AI比人脑更强,因为被植入思维模型【51】效率思维模型
  • Conda 环境离线迁移实战:解决生产环境网络限制的高效方案20250409
  • Redis缓存之预热、击穿、穿透、雪崩
  • yolov8几种模型参数model 解读
  • 【MYSQL从入门到精通】数据类型及建表
  • 牛客 小红杀怪
  • 合肥网站建设sina/手机网站模板免费下载
  • 郑州网站建设技术外包/hao123主页
  • 怎么给别人做网站优化/2023年10月疫情恢复
  • wordpress 敏感词过滤/快速优化seo软件
  • 个人网站咋推广啥叫流量/品牌推广策略与方式
  • 58网站一起做网店/如何做网站建设