《设计模式》读书笔记
1. 总结
设计模式本质上是“可复用、可维护、可扩展、低耦合”代码的经验总结。
学习设计模式前,先明确“面向过程”和“面向对象”的差别:
- 面向过程:以函数为核心,关注“怎么做”(步骤)。
- 面向对象:以对象为核心,关注“谁来做”(职责)。
面向对象三大特性:
- 封装:把数据和行为放在一起。
- 继承:子类继承父类能力并可扩展。
- 多态:同一接口,不同实现。
2. 七大设计原则
2.1 开闭原则
对扩展开放,对修改关闭。尽量通过“新增”来支持新需求,而不是修改稳定代码。
2.2 里氏替换原则
子类必须可以替换父类,且不破坏原有行为约定。
2.3 依赖倒置原则
高层模块依赖抽象,不依赖具体实现。
2.4 接口隔离原则
接口要小而专一,避免“胖接口”。
2.5 单一职责原则
一个类只负责一类职责(只应有一个引起它变化的原因)。
2.6 迪米特法则(最少知道原则)
对象之间尽量少直接交互,降低耦合。
2.7 合成/聚合复用原则
优先用组合(has-a)复用,而不是继承(is-a)。
3. 设计模式分类总览
3.1 创建型(关注“怎么创建对象”)
- 单例模式
- 工厂方法模式
- 抽象工厂模式
- 建造者模式
- 原型模式
3.2 结构型(关注“怎么组合对象/类”)
- 适配器模式
- 桥接模式
- 组合模式
- 装饰模式
- 外观模式
- 享元模式
- 代理模式
3.3 行为型(关注“对象如何协作”)
- 职责链模式
- 命令模式
- 解释器模式
- 迭代器模式
- 中介者模式
- 备忘录模式
- 观察者模式
- 状态模式
- 策略模式
- 模板方法模式
- 访问者模式
4. 模式笔记(按原笔记顺序整理)
4.1 简单工厂模式
定义:定义一个工厂类,根据参数创建不同具体对象。
示例:计算器支持 + - * /。
优点:
- 创建逻辑集中,便于管理。
- 客户端不用关心具体创建细节。 缺点:
- 新增功能要改工厂判断逻辑,违背开闭原则。
- 工厂职责容易过重。
4.2 策略模式
定义:将一组算法分别封装并可互换,算法变化不影响使用方。
示例:超市活动(满减、打折、积分)。
优点:
- 新增策略通常只需加类,不改旧逻辑。
- 策略可复用、可独立测试。 缺点:
- 策略多时类数量增加。
- 客户端需要理解并选择策略。
4.3 装饰模式
定义:不改原对象,动态叠加新功能。
示例:换装系统(衣服、裤子、帽子、鞋子自由组合)。
优点:
- 动态扩展,灵活组合。
- 符合开闭原则。 缺点:
- 装饰层级过多时理解成本上升。
4.4 代理模式
定义:为真实对象提供代理,控制访问并可附加增强逻辑。
示例:代送礼物。
优点:
- 职责分离(代理做控制,真实对象做业务)。
- 可加权限、日志、缓存等横切能力。 缺点:
- 增加系统复杂度。
4.5 模板方法模式
定义:定义算法骨架,具体步骤延迟到子类实现。
示例:简历模板(固定字段 + 可变工作经历)。
优点:
- 公共逻辑上提,减少重复代码。
- 扩展新变体方便。 缺点:
- 子类较多时维护成本上升。
4.6 外观模式
定义:给复杂子系统提供统一、简单入口。
示例:基金申购(用户只关心买入/卖出,不关心底层选股)。
优点:
- 降低使用门槛。
- 客户端与子系统解耦。 缺点:
- 外观类可能膨胀。
- 子系统变动可能影响外观层。
4.7 建造者模式
定义:将复杂对象的构建过程与表示分离。
示例:汉堡制作流程固定,不同品牌可复用流程。
优点:
- 构建过程可控,步骤清晰。
- 同流程可产出不同结果。 缺点:
- 引入建造者/指挥者,结构更复杂。
4.8 观察者模式
定义:一对多依赖,主题状态变化后自动通知观察者。
示例:老板回公司,员工停止摸鱼。
优点:
- 新增观察者不改主题。
- 发布订阅解耦。 缺点:
- 观察者过多时通知成本高。
- 时序处理不当会出现状态一致性问题。
4.9 工厂方法模式
定义:定义创建接口,由子类决定实例化哪种产品。
优点:
- 符合开闭原则。
- 解耦创建与使用。 缺点:
- 类数量增加。
4.10 抽象工厂模式
定义:创建“同一产品族”的一组相关对象。
示例:Windows/Mac 风格 UI(按钮 + 复选框)成套输出。
优点:
- 产品族一致性好,不易风格冲突。
- 符合开闭原则。 缺点:
- 结构比工厂方法更复杂。
4.11 状态模式
定义:对象内部状态变化时,行为随之变化。
示例:上班状态(上午/下午/加班)行为不同。
优点:
- 消除大量 if/else。
- 状态职责清晰,便于维护。 缺点:
- 状态类增多。
4.12 适配器模式
定义:把不兼容接口转换成目标接口。
示例:球场翻译,让中国球员和美国教练协作。
优点:
- 兼容旧系统,减少改造成本。
- 提升复用性。 缺点:
- 增加一层间接调用和复杂度。
4.13 备忘录模式
定义:在不破坏封装的前提下保存并恢复对象状态。
示例:游戏存档/读档。
优点:
- 支持撤销与恢复。
- 封装性好。 缺点:
- 状态多时内存开销大。
4.14 组合模式
定义:把对象组织成树形结构,表达“部分-整体”。
示例:文件夹与文件。
优点:
- 客户端可统一处理单个对象与组合对象。
- 扩展节点方便。 缺点:
- 设计不当会让职责边界模糊。
4.15 迭代器模式
定义:顺序访问聚合对象元素,不暴露内部结构。
示例:售票员遍历车上乘客。
优点:
- 遍历逻辑与集合结构分离。
- 符合开闭原则。 缺点:
- 简单场景可能显得偏重。
4.16 单例模式
定义:保证一个类仅有一个实例,并提供全局访问点。
示例:数据库连接池管理器。
优点:
- 避免重复创建。
- 统一共享状态。 缺点:
- 可能引入全局状态问题。
- 测试和扩展不够灵活。
4.17 桥接模式
定义:分离抽象与实现,让两个维度独立变化。
示例:形状(圆/方)与颜色(红/蓝)解耦组合。
优点:
- 组合爆炸问题明显缓解。
- 扩展维度互不影响。 缺点:
- 需要提前识别变化维度。
4.18 命令模式
定义:把请求封装为对象,支持排队、记录、撤销。
示例:遥控器按钮控制开灯/关灯。
优点:
- 请求发送者与执行者解耦。
- 易于扩展和记录操作。 缺点:
- 命令类数量增加。
4.19 职责链模式
定义:多个处理者串成链,请求沿链传递直至被处理。
示例:加薪审批链(组长→主管→...)。
优点:
- 请求方与处理方解耦。
- 链路可灵活调整。 缺点:
- 链过长影响排查与性能。
4.20 中介者模式
定义:用中介对象封装对象间交互,避免对象互相直接引用。
示例:微信群中消息由群统一转发。
优点:
- 减少对象间网状依赖。
- 交互逻辑集中管理。 缺点:
- 中介者容易膨胀成“上帝对象”。
4.21 享元模式
定义:共享大量细粒度对象以节省内存。
示例:文档里大量重复字符共享内在状态。
优点:
- 显著降低内存消耗。
- 提升对象创建性能。 缺点:
- 内外状态拆分增加理解成本。
4.22 解释器模式
定义:定义语法规则并提供解释执行机制。
示例:解析并计算表达式 1 + 2 + 3。
优点:
- 语法扩展相对直接。
- 规则结构清晰。 缺点:
- 复杂语法会导致类爆炸。
4.23 访问者模式
定义:在不改变元素类的前提下,为元素结构新增操作。
示例:对 CPU/硬盘/主板新增“价格计算”“序列化输出”。
优点:
- 新增“操作”方便,符合开闭原则。
- 相关操作集中。 缺点:
- 新增“元素类型”困难。
- 可能破坏部分封装。
5. 学习建议
- 先掌握原则,再记模式,避免“为模式而模式”。
- 每学一个模式,至少回答三个问题:
- 解决了什么痛点?
- 代价是什么?
- 什么时候不该用?
- 先在小场景用(日志、优惠、审批、通知),再用于业务核心。