设计模式学习笔记
1. 单例模式(创建型)
确保一个类仅有一个实例,并为其提供全局访问的入口。
- 删除拷贝构造和赋值函数
- 默认构造函数私有
- 类内部自己保存唯一实例(static)
- 暴露静态接口用于外部获取实例
适用场景:1. 日志系统(希望日志写在同个地方);2. 线程池(全局唯一)...
- 优点
- 控制实例数量,避免重复创建,节省资源
- 方便全局访问
- 缺点
- 全局变量对象化增加维护难度
- 代码耦合度变高
- 多线程下需谨慎处理
2. 原型模式(创建型)
复制已有对象按需修改后得到
- 提供克隆接口,自行实现
适用场景:1. 对象创建代价高,创建逻辑复杂;2. 不清楚具体子类,但存在现成对象,可以直接克隆(比如CAD的clone接口)。
-
优点
- 简化负责对象创建
- 提高性能(某些场景下复制比重新构造高效)
- 运行场景灵活,比如适用场景2
- 对具体创建细节进行封装屏蔽
-
** 缺点**
- 有些对象与外界资源强绑定不适合复制(资源独占/上下文依赖)
- 深浅拷贝问题需要注意
3. 工厂方法模式(创建型)
父类定义工厂方法,子类进行对象创建
- 将对象创建延迟到子类
适用场景:1. 无法提前确定要创建对象的具体类型;2. 创建逻辑与业务逻辑解耦;3.框架留扩展点
-
优点
- 降低耦合
- 易于扩展
- 符合单一职责原则(业务类不负责创建)
-
缺点
- 类数量增加,层次更多
- 如果对象固定且少,并且没有扩展需求,工厂方法模式可能设计过度
4. 抽象工厂模式(创建型)
提供接口用于创建"一组"产品(与工厂方法模式区分,工厂方法模式负责创建一个产品)
- 生产多个相关对象
- 保证产品之间一致性
适用场景:1. 跨平台UI库;2. 主题系统;
-
优点
- 保证产品族间的一致性,且易于切换
-
缺点
- 新增产品族容易,但新增产品族接口麻烦
- 类数量增多
5. 建造者模式(创建型)
把一个复杂对象的构建过程拆开,一步一步构造,这样同样的构建过程可以生成不同表示的对象。
- 对象创建过程分步进行
- 同样的创建步骤,可以组合出不同结果
适用场景:1. 电脑组装;2. 表格筛选查询对象;
-
优点
- 减少构造函数参数,创建过程更清晰,可读性好
-
缺点
- 代码量增加
- 对于简单对象而言有点重
6. 适配器模式(结构型)
适配器转换,使接口符合客户需求。
- 不改变原有类代码,可复用已有功能
- 让原本接口不兼容的类可以在一起工作
适用场景:1. 封装第三方SDK;2. 旧接口升级;3. 项目重构时兼容旧代码;
-
优点
- 复用已有类,不用修改老代码,降低改动成本
- 将接口转换逻辑单独放在适配器中,逻辑更清晰
-
缺点
- 代码结构复杂度升高
- 需注意预防适配器臃肿
7. 装饰器模式(结构型)
给对象套层外壳(做装饰)
- 在不修改原类代码的情况下,动态地给对象增加功能
- 比直接用继承扩展更灵活
适用场景:1. UI组件增加边框、滚动条;2. IO流包装;
-
优点
- 复用已有类,不用修改老代码,降低改动成本
- 将接口转换逻辑单独放在适配器中,逻辑更清晰
-
缺点
- 代码结构复杂度升高
- 需注意预防适配器臃肿
8. 代理模式(结构型)
给对象提供中介,外部不直接访问真是对象,而是先访问代理对象,由代理对象决定访问权限、访问时机。
适用场景:1. 权限控制代理;2. 缓存代理;3. 远程代理;
-
优点
- 控制对象访问
- 支持延迟加载,提升性能
-
缺点
- 代理让调用关系多了一层,可能会带来臃肿
9. 外观模式(结构型)
简化适用,将系统内部复杂子系统封装起来,对外提供一个统一的简化接口
适用场景:1. 编译系统构建;2. 图形系统统一绘制入口;
-
优点
- 隐藏内部系统复杂性
- 降低调用方和子系统耦合
- 便于用户使用
-
缺点
- 无法处理用户想调用子系统细节能力的情况
10. 桥接模式(结构型)
把抽象和实现拆开,让其独立变化,再通过组合将两边连接起来。
适用场景:1. 系统内有多个独立变化维度;2. 想用组合代替大量继承;
-
优点
- 比纯继承更灵活
- 抽象和实现可以独立扩展
- 便于用户使用
-
缺点
- 系统结构多出一层抽象,可读性不如简单模式
11. 组合模式(结构型)
把单个对象和由多个对象组成的整体,用统一方式来处理。
适用场景:1. 对象之间有明显的树形层级结构;2. 存在部分-整体关系;
-
优点
- 统一单个对象和组合对象的使用方式
- 容易扩展新的节点类
-
缺点
- 系统结构多出一层抽象,可读性不如简单模式
12. 享元模式(结构型)
将大量对象中可共享的部分提取出来复用,避免重复创建。
适用场景:1. 文字编辑器中的字符对象;2. 地图上的重复图块;
-
优点
- 节省内存和对象创建的成本
- 共享状态集中管理,更高效
-
缺点
- 注意区分内部状态和外部状态
13. 策略模式(行为型)
把多种可替换的行为封装成独立策略,在运行时按需要选择其中一种。
适用场景:1. 排序策略;2. 支付策略;
-
优点
- 算法/行为可以独立扩展
- 符合开闭原则
- 调用方和具体实现解耦
14. 模板方法模式(行为型)
父类先定义好整体流程,子类只负责实现其中的某些具体步骤。
适用场景:1. 文档生成/导出流程(处理流程大体一致可复用);
-
优点
- 复用公共流程代码
- 执行顺序可控
-
缺点
- 不适合差异较大的场景
- 依赖继承,灵活性不高
15. 观察者模式(行为型)
当一个对象状态变化时,自动通知所有订阅它的对象。
适用场景:1. UI按钮点击事件;2. 消息订阅;
-
优点
- 支持一对多通知,新增观察者方便
- 降低对象之间的耦合
-
缺点
- 调试时不容易直接看出时谁触发了谁
- 容易导致效率问题
- 销毁对象和取消订阅时需要注意
16. 迭代器模式(行为型)
在不暴露容器内部实现的前提下,按统一接口顺序访问容器中的元素。
适用场景:1. offset globalbuffer节点遍历;2. 图元集合遍历;
-
优点
- 隐藏容器内部实现
- 遍历逻辑可以独立出来
17. 责任链模式(行为型)
把多个处理对象连成一条链,让请求沿链传递,直到某个对象处理它为止。
适用场景:1. 请假审批流程;2. 异常处理链;
-
优点
- 请求发送者与接收者解耦
- 避免大量条件判断
- 很适合流程化处理
-
缺点
- 调试可能不够直观
- 链太长会影响理解和维护
18. 命令模式(行为型)
把一个操作请求封装成一个对象,从而让请求发送者和执行者解耦。
适用场景:1. 编辑器的撤消重做;2. 菜单命令;
-
优点
- 请求调用者和执行者解耦
- 适合做操作记录、队列、宏命令
-
缺点
- 如果将每个小操作都做成类,代码量会变很大
19. 备忘录模式(行为型)
在不暴露对象内部实现的情况下,保存对象过去的状态,并在需要时恢复。
适用场景:1. 游戏存档;2. 配置修改前保存旧状态;
-
优点
- 方便恢复历史状态
- 将状态保存逻辑和对象本身业务逻辑分开
-
缺点
- 需对历史记录进行管理,避免导致性能、内存占用劣化
20. 状态模式(行为型)
同一个对象,在不同状态下,对同一个请求的反应不一样。
适用场景:1. 订单状态;2. 电梯状态;3. 网络连接状态;
-
优点
- 将不同状态下的行为拆分开,直观清晰
- 符合开闭原则
-
缺点
- 状态之间切换导致理解成本升高
21. 访问者模式(行为型)
元素本身不负责做很多不同事情,而是让外部访问者来对它做事。
适用场景:1. 图形对象导出、打印、计算面积;2. 报表对象做多种统计分析;
-
优点
- 便于操作新增、集中管理
- 减少元素类里堆太多无关方法
-
缺点
- 新增元素类型较麻烦
22. 中介者模式(行为型)
大家不直接彼此联系,而是都通过"中间协调者"来配合。
适用场景:1. 聊天室系统;2. 智能家居中控;
-
优点
- 降低对象之间的耦合
- 让各个对象的职责更单一
-
缺点
- 系统的复杂度只是从对象之间转移到了中介者身上
22. 解释器模式(行为型)
给一套规则写"语法类",然后让程序自己去读懂并执行这些规则。
适用场景:1. 数学表达式解释;2. 正则或过滤表达式的小型实现;
-
优点
- 扩展某些新规则比较自然
- 适合表示树形表达式结构
-
缺点
- 语法一复杂,结构会迅速变得很绕
- 不适合大型复杂语言,且维护成本高