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