本篇介绍软件设计原则之一SRP:单一职责原则。
SRP:单一职责原则
一个类应该只有一个发生变化的原因。
Why
为何把职责分离到单独的类中很重要呢?因为每一个职责都是变化的一个轴线。当需求变化时,该变化会反映为类的职责变化。如果一个类承担了多于一个职责,那么引起它变化原因就会有多个。
如果一个类承担的职责过多,就等于把这些职责耦合在了一起。一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意向不到的破坏。
如何定义职责
在SRP中,我们把职责定义为变化的原因。如果你能想到多于一个动机去改变一个类,那么这个类就多于一个的职责。有时,我们很难注意到这一点。我们习惯于以组的形式去考虑职责。
Modem.java
代码语言:javascript复制 public interface Modem{
void dial(String pno);
void hangup();
void send(char c);
char recv();
}
接口中却显示出了两个职责。第一个职责连接管理,第二个数据通信。dial和hangup函数进行连接处理,而send和recv函数进行数据通信。
那么这两个职责应该分开吗?这依赖于程序变化的方式。如果应用程序的变化会影响连接函数的签名,那么这个设计就具有僵化性的臭味,因为调用send 和 recv的类必须要重新编译、部署的次数常常会超过我们希望的次数。这种情况下,这两个职责应该被分离。
另一方面,如果应用程序变化方式总是导致这两个职责的同时变化,那么就不必分离它们,实际上,分离他们就会具有不必要的复杂性的臭味。
有个推论是:仅当变化发生时,变化的轴线才具有实际意义。如果没有征兆,那么应用SRP或者任何其他原则都是不明智的。
分离耦合的职责
上面,我们把两个职责都耦合进了modem的实现类中。这不是所希望的,但是或许是必要的。常常会有一些和硬件和操作系统的细节有关的原因,迫使我们不愿耦合在一起的东西耦合在了一起。然而对于应用的其余部分来说,通过分离它们的接口我们已经解耦了概念。已经把丑陋的部分隐藏起来了。其丑陋性不会污染应用程序的其他部分。
SRP是所有原则中最简单的原则之一,也是最难正确运用的原则之一。我们会自然地把职责结合在一起。软件设计真正要做的许多工作,就是发现职责并把那么职责相互分离。事实上,我们将要论述的其余原则都会以这样或那样的方式回到这个问题上。
结论
职责定义为变化的原因,对于一组的耦合的职责设计要不要分离,具体要看职责是不是同时变化,我们可以通过接口来分离耦合的职责。