名称:设计模式
描述:在以下情况下使用:设计软件架构、重构代码结构、解决重复出现的设计问题,或者当代码出现症状如紧耦合、僵化的层次结构、分散的责任或难以测试的组件时。也可用于在架构方法之间进行选择或审查代码以进行结构改进。
设计模式
概述
设计模式是针对重复出现的软件设计问题的成熟解决方案。它们提供了讨论设计的共享词汇,并捕捉了通过数十年实际使用提炼的集体智慧。
核心理念: 模式是您根据上下文适应的模板,而不是复制的蓝图。在它真正简化您的设计时使用正确的模式——而不是为了炫耀或过度工程化。
基础原则
这些原则支撑所有好的设计:
| 原则 |
含义 |
违反症状 |
| 封装变化的部分 |
将变化的部分与稳定的部分隔离 |
变化波及整个代码库 |
| 面向接口编程 |
依赖抽象,而非具体实现 |
无法交换实现 |
| 组合优于继承 |
通过组合对象来构建行为 |
深层的僵化类层次结构 |
| 松耦合 |
最小化对象之间的相互依赖 |
更改一个事物会破坏另一个 |
| 开闭原则 |
对扩展开放,对修改关闭 |
必须编辑现有代码以添加新功能 |
| 单一职责 |
每个类只有一个更改原因 |
类做太多事情 |
| 依赖倒置 |
高级模块不依赖低级模块 |
业务逻辑与基础设施耦合 |
模式选择指南
按问题类型
创建对象
├── 复杂/有条件的创建 ──────────→ 工厂方法
├── 相关对象家族 ───────────→ 抽象工厂
├── 逐步构建 ─────────────→ 建造者
├── 克隆现有对象 ────────────────→ 原型
└── 需要单一实例 ────────────────→ 单例(谨慎使用!)
结构化/组合对象
├── 不兼容的接口 ────────────────→ 适配器
├── 简化复杂子系统 ────────────────→ 外观
├── 树/层次结构 ──────────────→ 组合
├── 动态添加行为 ──────────────→ 装饰器
└── 控制对象访问 ──────────────→ 代理
管理通信/行为
├── 一对多通知 ──────────────→ 观察者
├── 将请求封装为对象 ───────→ 命令
├── 行为随内部状态变化 ─────→ 状态
├── 运行时交换算法 ──────────→ 策略
├── 带钩子的算法骨架 ─────────→ 模板方法
├── 减少N对N通信 ───────────→ 中介者
└── 顺序处理器 ───────────────────→ 责任链
管理数据访问
├── 抽象数据源 ──────────────────→ 仓库
├── 跟踪更改以实现原子提交 ───────→ 工作单元
├── 确保对象身份 ────────────────→ 身份映射
├── 延迟昂贵加载 ────────────────→ 懒加载
├── 映射对象到数据库 ───────────────→ 数据映射器
└── 为传输塑造数据 ───────────────→ 数据传输对象
按症状
| 症状 |
考虑 |
| 巨大的switch/if-else基于类型 |
策略、状态或多态 |
| 类间重复代码 |
模板方法、策略 |
| 需要通知许多对象更改 |
观察者 |
| 复杂的对象创建逻辑 |
工厂、建造者 |
| 添加功能使类膨胀 |
装饰器 |
| 第三方API不适合您的代码 |
适配器 |
| 组件间依赖过多 |
中介者、外观 |
| 没有数据库/网络无法测试 |
仓库、依赖注入 |
| 需要撤销/重做 |
命令 |
| 对象行为依赖于状态 |
状态 |
| 请求需要由多个处理器处理 |
责任链 |
领域逻辑:事务脚本与领域模型
| 因素 |
事务脚本 |
领域模型 |
| 逻辑复杂度 |
简单(< 500行) |
复杂,许多规则 |
| 业务规则 |
少,直接 |
多,相互作用 |
| 操作 |
以CRUD为主 |
丰富行为 |
| 团队/时间线 |
小团队,快速交付 |
长期维护 |
| 测试 |
集成测试 |
领域单元测试 |
经验法则: 从事务脚本开始。当过程代码难以维护时,重构为领域模型。
快速参考
第1层:基本模式(首先掌握)
第2层:结构模式
第3层:企业/架构模式
其他重要模式
常见错误
| 错误 |
症状 |
修复 |
| 模式过度使用 |
简单操作需要导航许多类 |
仅在解决真实问题时使用 |
| 错误模式 |
代码感觉强制、笨拙 |
重新检查实际问题 |
| 继承滥用 |
深层层次结构、脆弱的基类 |
优先组合(策略、装饰器) |
| 单例滥用 |
全局状态、隐藏依赖、难以测试 |
改用依赖注入 |
| 过早抽象 |
接口只有单一实现 |
等待真正需要变化时 |
要识别的反模式
- 上帝对象: 一个类做所有事情 → 使用单一职责原则拆分
- 贫血领域模型: 对象只是数据袋 → 将行为移到对象中
- 金锤: 到处使用相同模式 → 匹配模式到问题
- 熔岩流: 没人移除的废弃代码 → 删除它,版本控制系统有备份
现代变体
| 现代模式 |
基于 |
描述 |
| 依赖注入 |
策略 + 工厂 |
容器创建并注入依赖 |
| 中间件 |
装饰器 + 责任链 |
请求/响应管道 |
| 事件溯源 |
命令 |
将状态更改存储为事件 |
| CQRS |
命令/查询分离 |
分离读写模型 |
| 钩子(React/Vue) |
观察者 + 策略 |
功能性生命周期订阅 |
实现检查清单
在实现模式之前:
- [ ] 模式解决了此代码库中的真实问题
- [ ] 考虑了更简单的替代方案
- [ ] 权衡在此上下文中可接受
- [ ] 团队理解该模式
- [ ] 不会过度工程化解决方案