单一职责原则
了解单一职责原则,以及它如何帮助你构建更优秀的软件架构。
在上一章中,我们讨论了使用分层架构时可能出现的问题。本章将介绍一种替代方案。我们将首先探讨SOLID原则中的两个原则,然后应用它们来构建一个“整洁”或“六边形”架构,以解决分层架构存在的问题。
SOLID
SOLID 包含以下五个原则:
- S 单一职责原则(Single Responsibility Principle)
- O 开闭原则(Open-Closed Principle)
- L 里氏替换原则(Liskov Substitution Principle)
- I 接口隔离原则(Interface Segregation Principle)
- D 依赖倒置原则(Dependency Inversion Principle)
你可以参考 Robert C. Martin 的《整洁架构》一书或维基百科了解更多关于这些原则的内容。
SRP(单一职责原则)
软件开发领域的每个人可能都知道 #key# SRP:单一职责原则 #key#,或者至少假装了解它。
对该原则的一种常见理解是:
一个组件只应做一件事,并把它做好。
这是一条不错的建议,但它并不是 #key# SRP:单一职责原则 #key# 的真正含义。
“只做一件事”其实是对“单一职责”最直观的解释,因此人们常常如此理解该原则也就不奇怪了。但我们必须意识到,#key# SRP:单一职责原则 #key# 这个名称本身具有误导性。
#key# SRP:单一职责原则 #key# 的正确定义是:
一个组件应当只有一个被修改的原因。
由此可见,“职责”实际上应理解为“被修改的原因”,而不是“只做一件事”。也许我们应该把这个原则更名为“单一修改原因原则”。
如果一个组件只有一个被修改的原因,那么它很可能确实只完成一项功能,但更重要的是,它的变更诱因是唯一的。
这对我们的架构意味着什么?
如果某个组件只有一个被修改的原因,那么当我们因其他任何原因修改系统时,就完全不必担心这个组件会受到影响——因为我们知道它的行为仍将保持预期。
遗憾的是,在代码中,一个组件的“修改原因”很容易通过其对其他组件的依赖关系传播出去(见图6)。
在上图中,组件 A 依赖于多个其他组件(直接或间接),而组件 E 则没有任何依赖。
修改组件 E 的唯一原因,是由于新需求导致其自身功能需要变更。而组件 A 则可能因为其所依赖的任意一个组件发生变化,而被迫随之修改。
违反 SRP
许多代码库随着时间推移变得越来越难以修改,因而维护成本也越来越高,其根本原因就在于违反了 #key# SRP:单一职责原则 #key#。随着时间推移,组件积累的修改动因越来越多。一旦一个组件拥有大量变更理由,修改它就可能导致其他组件出错。
