首页 > 代码库 > 单一职责原则

单一职责原则

定义:

      该原则规定每个类都应该只有一个单一的功能,并且该功能应该由这个类完全封装起来。

何为职责?

      

既然是单一“职责”,那么职责即为被规定的因素。

  • 概括:"功能(职责)"为改变的原因,一个类或者模块应该有且只有一个改变的原因。

 

例子一:

  • 如下图农活责任所示,耕菜地和耕水田即为牛和耕地机的职责,即为这个对象存在的原因(下面将来讨论这个关系图)。

                                               技术分享

看上图农活责任,晃眼一看我们会决定这是对的!但仔细一分析农活接口其中包含的耕菜地和耕水田两个责任。

  • 牛耕水田,但它耕不动菜地,只能调用耕水田的接口,因此耕菜地的接口对于牛来说就是多余的。但耕地机即能耕菜地,也能耕水田。这就像是牛本来是耕田的,我们却说它还能去耕菜地,耕地机能做的事情,老牛表示无能为力!

  • 这样违反了SRP,导致了严重的问题。因为我们给牛保留了一个多余而不会完成的责任,这让我们每次提到牛不仅说它能耕水田还能耕菜地。这让我们对牛的描述更加的复杂而没有准确性。程序也时这样,当没用的责任增加,就会让相应的类都变得臃肿腐臭。当我们要添加牛要耕后要吃草,耕地机耕地后要加油时,继续往农活接口中添加,这样使得农活什么都能干,使得后期修改维护等难度太大。

  • 如果不分离责任,在不断变化和添加的需求面前,责任之间耦合度强导致我们的程序更加的脆弱

                                                         技术分享

如上图将两个责任分离,牛实现耕水田的时候,不会知道也不会去在意耕菜地,分离了责任,该做的才做,不做的不用管

例子二:

      电话这玩都离不开的。电话通话的时候有四个过程发生:拨号、通话、回应、挂机。如下面的接口代码:

interface IPhone {
  void dial(String pno);//拨号
  void chat(Object o);//发送消息
  void hangup();//挂断
}

   大家看下这个接口有没有问题?我相信大部分读者都会说没有问题呀,我就是这么做的呀。是的,这个接口几乎没有问题。但是,单一职责原则要求一个接口或类只有一个原因引起变化,也就是一个接口或类只有一个职责。

       这个接口中显示了两个职责,一个是连接管理,一个是数据通信。dial和hangup函数进行调制解调器的连接处理,而chat函数进行数据的通信。

这两个责任应该被分开吗?这决定于应用程序以何种方式变化。如果应用程序的变化会影响连接函数的部署,那么这个设计就具有僵化性的臭味。因为调用send和recv的类必须要重新编译连接处理函数,部署的次数常常会超过我们希望的次数。在这种情况下,这两个职责应该被分离。如图下图所示,这样避免了客户应用程序和这两个职责耦合在一起。

 技术分享

 

   如果应用程序的变化方式总是会导致两个职责同时变化,那么就不必分离他们,分离后会导致不必要的复杂性。

总结

  • SRP为最简单的原则,也是最难运用好的原则
  • 软件设计真正要做的其实就是发现责任并把那些责任分离
  • 其他原则都将能追溯到SRP
  • 大道至简,只有不断在代码中运用才能真正体会其中的奥妙

 

参考

[1]《设计模式之》第1章 单一职责原则

 

单一职责原则