设计模式总结

发布于:2025-08-30 ⋅ 阅读:(12) ⋅ 点赞:(0)

一、总结

模式类型 模式名称 核心意图 优点 缺点 适用场景
创建型 工厂模式 定义创建对象的接口,由子类决定实例化哪个类 解耦创建与使用,便于扩展 新增产品需新增工厂,类数量增多 产品种类较少,创建逻辑较复杂时(如日志工厂、数据库连接工厂)
抽象工厂模式 提供创建一系列相关/依赖对象的接口,无需指定具体类 保证产品族一致性,隔离具体类 新增产品族困难,结构复杂 需创建多个相关产品(如UI组件库:Windows/Mac风格的按钮、文本框)
单例模式 保证类仅有一个实例,并提供全局访问点 控制资源访问,避免重复创建 破坏单一职责,可能导致全局状态,测试困难 全局资源管理(如配置中心、线程池、日志器)
原型模式 通过复制现有实例创建新对象,避免重复初始化 提高创建效率,简化复杂对象创建 深拷贝复杂对象时实现困难 对象创建成本高(如大对象、数据库查询结果),或需动态生成相似对象时
建造者模式 将复杂对象的构建与表示分离,分步构建对象 控制构建过程,灵活组合部件 产品差异大时,建造者类膨胀 复杂对象构建(如文档、报表、汽车组装)
结构型 适配器模式 将一个类的接口转换为客户端期望的另一个接口,解决兼容性问题 复用现有类,透明适配,不修改源码 过多适配器会增加系统复杂度 接口不兼容的类需要协同工作(如老系统对接新接口、第三方库适配)
桥接模式 将抽象与实现分离,使两者可独立变化 减少类爆炸,提高扩展性 增加系统抽象层次,理解难度加大 多维度变化的场景(如形状+颜色、消息类型+发送方式)
装饰器模式 动态给对象添加额外功能,不改变其结构 灵活扩展功能,比继承更灵活 多层装饰可能导致调试困难 需动态扩展功能且不希望修改原类(如IO流包装、日志增强、权限控制)
组合模式 将对象组合成树形结构,统一处理单个对象和组合对象 简化客户端代码,符合开闭原则 设计复杂,限制组合对象类型时较麻烦 树形结构场景(如文件系统、组织架构、菜单导航)
外观模式 为子系统提供统一接口,简化访问复杂度 降低耦合,简化调用 可能成为“上帝类”,违背单一职责 子系统复杂,需对外提供简单接口(如第三方SDK封装、系统入口封装)
享元模式 复用细粒度对象,减少内存占用 减少对象数量,提高性能 引入工厂和池,增加系统复杂度 大量相似对象场景(如文字处理中的字符、游戏中的粒子效果、缓存)
代理模式 为对象提供代理,控制对原对象的访问 隔离访问,增强功能(如权限、缓存、日志) 增加代理层,可能降低性能 需控制访问(如远程代理、安全代理、延迟加载)
行为型 职责链模式 将请求沿处理链传递,直到被处理 解耦请求发送者与接收者,动态调整链 可能导致请求未被处理,调试困难 多对象可处理同一请求(如日志级别过滤、审批流程、异常处理)
命令模式 将请求封装为对象,使请求可参数化、队列化 支持撤销/重做,解耦调用者与执行者 类数量增多,命令复杂时理解困难 需记录请求、支持事务(如GUI按钮命令、任务调度、命令日志)
解释器模式 定义语言语法,构建解释器解析句子 易于扩展语法,灵活处理特定语言 复杂语法会导致类膨胀,效率低 简单语法解析(如表达式计算、规则引擎、正则表达式)
迭代器模式 提供遍历聚合对象的统一接口,不暴露内部结构 统一遍历方式,简化客户端 增加系统复杂度,对于简单集合可能多余 需遍历不同聚合结构(如集合框架、树结构遍历)
中介者模式 用中介者封装对象间的交互,减少直接耦合 简化对象关系,集中控制交互 中介者可能成为瓶颈,复杂度集中 对象间交互复杂(如聊天室、GUI组件交互、分布式系统协调)
备忘录模式 捕获对象状态并保存,以便后续恢复 实现状态恢复,不破坏封装 消耗资源,状态过大时效率低 需要撤销/回滚操作(如编辑器撤销、游戏存档、事务回滚)
观察者模式 定义一对多依赖,一个对象变化时通知所有依赖者 解耦主题与观察者,支持动态订阅 通知顺序不确定,可能导致循环依赖 事件通知场景(如消息订阅、GUI事件响应、状态监控)
状态模式 允许对象在内部状态变化时改变行为,仿佛修改了类 封装状态转换,清晰管理不同状态行为 状态多时分支多,类数量增加 对象行为依赖于状态(如订单状态流转、电梯状态控制、有限状态机)
策略模式 定义算法家族,封装并动态切换 算法可替换,避免多重条件判断 客户端需知道所有策略,增加理解成本 多种算法可选(如排序算法、支付方式、折扣策略)
模板方法模式 定义算法骨架,子类实现具体步骤 复用骨架代码,强制算法结构 子类可能过多,修改骨架需修改抽象类 算法步骤固定但细节可变(如生命周期方法、报表生成步骤、流程模板)
访问者模式 分离数据结构与操作,在不修改类的情况下添加新操作 集中管理操作,易于扩展新操作 数据结构变化时需修改所有访问者,违反开闭 稳定的数据结构+多变的操作(如文档解析、AST语法树分析、报表统计)

二、分类框架

23 种模式本质是按解决的核心问题场景划分的,先明确分类能快速缩小选型范围,避免混乱

  1. 模式分类逻辑
    • 创建型:关注对象创建机制,解决“如何创建对象”的问题,降低耦合。
    • 结构型:关注对象/类的组合关系,解决“如何组装对象”的问题,优化结构。
    • 行为型:关注对象间的交互,解决“如何协作”的问题,优化行为。
  2. 常见模式组合
    • 抽象工厂 + 桥接模式:处理多维度产品变化(如跨平台组件库)。
    • 装饰器 + 策略模式:动态扩展功能并切换算法(如带缓存的支付系统)。
    • 观察者 + 中介者模式:处理复杂事件通知(如分布式系统中的事件总线)。
  3. 反模式警惕
    • 单例模式滥用导致全局状态污染。
    • 装饰器过度嵌套导致“装饰地狱”。
    • 中介者模式膨胀为“万能类”。

三、易混淆模式的核心区分

很多模式看似相似,实则解决的问题场景完全不同

易混淆组 核心区分点
工厂方法 VS 抽象工厂 工厂方法:单产品族(如只造“手机”,不同工厂造“小米手机”“华为手机”);
抽象工厂:多产品族(如造“手机+平板”,一个工厂造“小米手机+小米平板”,另一个造“华为手机+华为平板”)
策略模式 VS 状态模式 策略模式:主动选择算法(客户端决定用哪个策略,如“导航选步行/开车”);
状态模式:状态驱动行为(对象自身状态变化触发行为变化,如“订单从待支付→已支付→已发货”,状态变了行为自动变)
装饰器模式 VS 代理模式 装饰器模式:增强功能(不改变原对象核心逻辑,只叠加新功能,如“给手机贴钢化膜(防刮)+戴壳(防摔)”);
代理模式:控制访问(替原对象做“权限校验、延迟加载、日志”等非功能逻辑,如“代理对象先校验用户权限,再调用原对象接口”)
适配器模式 VS 外观模式 适配器模式:解决“不兼容”(让两个已有、不兼容的接口能一起工作,如“USB-C转HDMI适配器”);
外观模式:简化接口(给复杂子系统封装一个统一入口,如“智能家居中控,一键控制灯光+空调+窗帘”,子系统本身是兼容的)

四、实践中的核心注意事项(避免踩坑)

  1. 设计模式不是“银弹”,拒绝过度设计
    不要为了用模式而用模式!比如:简单的对象创建(如只new一个对象,无变化),没必要用工厂模式;只有一个类的系统,没必要用外观模式。过度使用会增加代码复杂度(如单例模式会增加测试难度,装饰器多层嵌套会让调试变难)。
  2. 优先遵循设计原则,再匹配模式
    所有模式都是“设计原则的落地实现”:
    • 开闭原则(对扩展开放、对修改关闭)→ 装饰器、策略、观察者等;
    • 单一职责(一个类只做一件事)→ 策略、职责链等;
    • 依赖倒置(依赖抽象,不依赖具体)→ 工厂方法、抽象工厂等。
      先明确“我要解决的问题违反了哪个原则”,再找对应的模式,比死记模式更高效。
  3. 模式可以组合使用(实际项目更常见)
    单一模式难以解决复杂问题,常见组合场景:
    • 建造者模式 + 模板方法:建造者的“构建步骤”用模板方法固定,具体实现交给子类(如“造房子的步骤(打地基→砌墙→封顶)固定,子类实现‘盖别墅’‘盖公寓’的具体细节”);
    • 观察者模式 + 中介者模式:多个观察者之间不直接通信,通过中介者转发消息(如“微信群聊,群成员(观察者)发消息,由群(中介者)转发给其他人,避免成员间耦合”);
    • 单例模式 + 工厂模式:工厂本身做成单例(如“全局只有一个数据库连接工厂”)。
  4. 特殊模式的使用限制
    • 单例模式:注意线程安全(C++需加锁,Java用枚举或静态内部类),且避免用于“有状态”的对象(如存储用户会话,会导致多用户数据混乱);
    • 享元模式:仅适用于“大量重复、细粒度对象”(如围棋棋子、字符串常量池),否则缓存的开销可能大于收益;
    • 解释器模式:只用于简单语法(如表达式解析),复杂语法(如SQL解析)建议用专业解析工具(ANTLR),避免手写解释器导致代码臃肿。

五、学习建议

  1. 先“理解场景”,再“记结构”:不要死记UML类图,先想“这个模式解决了什么痛点”(比如代理模式解决“不想让客户端直接访问原对象”的痛点),再看类图如何支撑这个痛点。
  2. 结合业务练手:比如“电商订单状态流转”用状态模式,“支付方式选择”用策略模式,“商品SKU创建(多属性组合)”用建造者模式,将模式和实际业务绑定记忆。
  3. 警惕“设计模式教条化”:小项目或简单场景,“能用if-else解决的,就不用策略模式”,过度追求设计优雅反而会降低开发效率。设计模式的核心是“平衡灵活性和复杂度”。

网站公告

今日签到

点亮在社区的每一天
去签到