软件设计原则之SRP:单一职责原则

Posted by Coderidea on November 21, 2020

本篇介绍软件设计原则之一SRP:单一职责原则。

SRP:单一职责原则

一个类应该只有一个发生变化的原因。

Why

为何把职责分离到单独的类中很重要呢?因为每一个职责都是变化的一个轴线。当需求变化时,该变化会反映为类的职责变化。如果一个类承担了多于一个职责,那么引起它变化原因就会有多个。

如果一个类承担的职责过多,就等于把这些职责耦合在了一起。一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意向不到的破坏。

如何定义职责

在SRP中,我们把职责定义为变化的原因。如果你能想到多于一个动机去改变一个类,那么这个类就多于一个的职责。有时,我们很难注意到这一点。我们习惯于以组的形式去考虑职责。

Modem.java

  public interface Modem{
   void dial(String pno);
   void hangup();
   void send(char c);
   char recv();
  }

接口中却显示出了两个职责。第一个职责连接管理,第二个数据通信。dial和hangup函数进行连接处理,而send和recv函数进行数据通信。

那么这两个职责应该分开吗?这依赖于程序变化的方式。如果应用程序的变化会影响连接函数的签名,那么这个设计就具有僵化性的臭味,因为调用send 和 recv的类必须要重新编译、部署的次数常常会超过我们希望的次数。这种情况下,这两个职责应该被分离。

另一方面,如果应用程序变化方式总是导致这两个职责的同时变化,那么就不必分离它们,实际上,分离他们就会具有不必要的复杂性的臭味。

有个推论是:仅当变化发生时,变化的轴线才具有实际意义。如果没有征兆,那么应用SRP或者任何其他原则都是不明智的。

分离耦合的职责

上面,我们把两个职责都耦合进了modem的实现类中。这不是所希望的,但是或许是必要的。常常会有一些和硬件和操作系统的细节有关的原因,迫使我们不愿耦合在一起的东西耦合在了一起。然而对于应用的其余部分来说,通过分离它们的接口我们已经解耦了概念。已经把丑陋的部分隐藏起来了。其丑陋性不会污染应用程序的其他部分。

SRP是所有原则中最简单的原则之一,也是最难正确运用的原则之一。我们会自然地把职责结合在一起。软件设计真正要做的许多工作,就是发现职责并把那么职责相互分离。事实上,我们将要论述的其余原则都会以这样或那样的方式回到这个问题上。

结论

职责定义为变化的原因,对于一组的耦合的职责设计要不要分离,具体要看职责是不是同时变化,我们可以通过接口来分离耦合的职责。

 

本文首发于个人微信公众号:webguan ;欢迎您的关注