单一职责原则
Posted 五岁i
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单一职责原则相关的知识,希望对你有一定的参考价值。
定义:
该原则规定每个类都应该只有一个单一的功能,并且该功能应该由这个类完全封装起来。
何为职责?
既然是单一“职责”,那么职责即为被规定的因素。
-
概括:"功能(职责)"为改变的原因,一个类或者模块应该有且只有一个改变的原因。
例子一:
-
如下图农活责任所示,耕菜地和耕水田即为牛和耕地机的职责,即为这个对象存在的原因(下面将来讨论这个关系图)。
看上图农活责任,晃眼一看我们会决定这是对的!但仔细一分析农活接口其中包含的耕菜地和耕水田两个责任。
-
牛耕水田,但它耕不动菜地,只能调用耕水田的接口,因此耕菜地的接口对于牛来说就是多余的。但耕地机即能耕菜地,也能耕水田。这就像是牛本来是耕田的,我们却说它还能去耕菜地,耕地机能做的事情,老牛表示无能为力!
-
这样违反了SRP,导致了严重的问题。因为我们给牛保留了一个多余而不会完成的责任,这让我们每次提到牛不仅说它能耕水田还能耕菜地。这让我们对牛的描述更加的复杂而没有准确性。程序也时这样,当没用的责任增加,就会让相应的类都变得臃肿腐臭。当我们要添加牛要耕后要吃草,耕地机耕地后要加油时,继续往农活接口中添加,这样使得农活什么都能干,使得后期修改维护等难度太大。
- 如果不分离责任,在不断变化和添加的需求面前,责任之间耦合度强导致我们的程序更加的脆弱
如上图将两个责任分离,牛实现耕水田的时候,不会知道也不会去在意耕菜地,分离了责任,该做的才做,不做的不用管
例子二:
电话这玩都离不开的。电话通话的时候有四个过程发生:拨号、通话、回应、挂机。如下面的接口代码:
interface IPhone { void dial(String pno);//拨号 void chat(Object o);//发送消息 void hangup();//挂断 }
大家看下这个接口有没有问题?我相信大部分读者都会说没有问题呀,我就是这么做的呀。是的,这个接口几乎没有问题。但是,单一职责原则要求一个接口或类只有一个原因引起变化,也就是一个接口或类只有一个职责。
这个接口中显示了两个职责,一个是连接管理,一个是数据通信。dial和hangup函数进行调制解调器的连接处理,而chat函数进行数据的通信。
这两个责任应该被分开吗?这决定于应用程序以何种方式变化。如果应用程序的变化会影响连接函数的部署,那么这个设计就具有僵化性的臭味。因为调用send和recv的类必须要重新编译连接处理函数,部署的次数常常会超过我们希望的次数。在这种情况下,这两个职责应该被分离。如图下图所示,这样避免了客户应用程序和这两个职责耦合在一起。
如果应用程序的变化方式总是会导致两个职责同时变化,那么就不必分离他们,分离后会导致不必要的复杂性。
总结
- SRP为最简单的原则,也是最难运用好的原则
- 软件设计真正要做的其实就是发现责任并把那些责任分离
- 其他原则都将能追溯到SRP
- 大道至简,只有不断在代码中运用才能真正体会其中的奥妙
参考
[1]《设计模式之》第1章 单一职责原则
以上是关于单一职责原则的主要内容,如果未能解决你的问题,请参考以下文章