1. 一个具体问题
一个报表类既计算价格,又查询数据库,还生成邮件。换邮件模板会触动价格测试,新增一种客户又要修改多个条件分支。团队希望通过“遵守 SOLID”改善,却先增加了十几个接口,让阅读路径变得更长。原则必须对应实际变化问题,才能有价值。
2. 一句话解释
SOLID 是五项面向对象设计原则的集合,用来减少变化传播和不合理依赖,而不是要求所有代码都拆成大量接口。
3. 出处与原意
Robert C. Martin 系统传播了相关设计原则,SOLID 缩写后来由 Michael Feathers 提出。五项分别是单一职责、开闭、里氏替换、接口隔离和依赖倒置;其中里氏替换关联 Barbara Liskov 等人的子类型研究,各项并非同一人同时发明。
4. 原理与机制
单一职责关注导致修改的责任来源;开闭原则希望稳定部分不因每次扩展而改动;里氏替换要求替代实现保持调用方依赖的行为契约;接口隔离减少使用者对无关能力的依赖;依赖倒置让重要业务规则依赖抽象契约,而非被某个技术细节绑住。它们都在控制变化的影响范围,但会增加类型、间接层和协作成本。只有存在具体变化压力时,新增边界才容易证明收益。
原则之间也可能出现张力。为了减少重复而扩大共享模块,可能把不同责任绑在一起;为了开闭而提前设计过多扩展点,又可能违背当前需求的简单性。遇到这种情况,应说明最可能发生的变化,以及愿意为隔离它支付多少间接成本。一次重构最好只解决已观察到的依赖问题,再用实际修改验证收益,而不是以五个字母作为机械评分表。
5. 一个完整案例
假设案例:报表系统每月换邮件格式,价格规则由财务独立调整。团队先把价格计算拆成可单独验证的模块,把发送动作放进通知适配器。后来加入短信渠道时,业务层只依赖“发送通知”这一最小能力,而不依赖某个邮件库。对于发送失败,两个实现都返回同样定义的结果,避免一个静默丢弃、另一个抛异常造成不可替换。团队没有把每个辅助函数都配一份接口,而是围绕变化频率和契约建立少数边界。
6. 适用条件与反例
适合长期维护、多个实现并存或变化来源不同的系统。短期脚本没有必要形式化使用全部五项。特别要避免把单一职责误解为“一类只能一个方法”,或把开闭原则误解为永不修改旧代码;错误抽象同样需要调整。
7. 今天可以尝试的行动
从最近三次需求变更中找出总被一起修改的文件和总被无关变化影响的测试。选择一处拆开不同变化来源,并为替代实现写清前置条件、返回结果与失败语义。用下一次真实变更是否更局部来评价效果。