SRC單一職責原則

1、定義

  一個類應該只有一個發生變化的緣由。測試

2、爲何要使用SRC

  由於每個職責都是變化的一個軸線。當需求變化時,這種變化就會反映爲類的職責的變化。若是一個類承擔了多於一個的職責,那麼引發它變化的緣由就會有多個。spa

  若是一個類承擔的職責過多,就等於把這些職責耦合在了一塊兒。一個職責的變化可能會消弱或抑制這個類完成其餘職責的能力。這種耦合會致使脆弱的設計,當變化發生時,設計會遭到意想不到的破壞。操作系統

3、案例演示

  考慮圖中的設計。設計

  

  Rectangle類具備兩個方法,一個方法把矩形繪製到屏幕上,另外一個方法則是計算矩形的面積。 如今有兩個應用程序使用Rectangle類。一個是利用Rectangle計算矩形面積,但不須要繪製矩形;另外一個應用程序可能會繪製矩形,也可能計算面積。3d

  這個設計違反了單一職責原則。Rectangle類具備兩個職責。第一個職責提供了矩形面積的計算;第二個職責提供了矩形繪製。 對於SRC的違反致使了一些嚴重的問題。代理

  對於這個違反了SRC的程序有如下幾點問題:code

  首先,咱們必須在左側的程序中包含進GUI代碼,即便咱們是不須要的。blog

  其次,若是右側程序的改變致使了Rectangle的改變,那麼這個改變會迫使咱們從新構建、測試和部署左側的程序。接口

   一個較好的設計就是把這兩個職責分離到以下圖所示的兩個徹底不一樣的類中。這個設計把Rectangle類中進行計算的部分移到了GeometricRectangle類中。如今矩形繪製方法的變化不會影響到左側的程序。開發

  

4、什麼是職責

  在SRC中,咱們把職責定義爲變化的緣由

  若是你可以想到多於一個的動機去改變一個類,那麼這個類就具備多於一個的職責。

  有時,咱們很難注意到這一點,咱們習慣於以組的形式去考慮職責。 例如,下面的Modem接口,大多數人認爲這個接口很是合理。該接口所聲明的4個方法確實是調制解調器所具備的功能 。

public interface Modem
{ 
    public void Dial(string pno); //鏈接 
    public void Hangup(); //斷開 
    public void Send(char c); //發送
    public char Recv(); //接收 
} 

  然而,該接口中卻顯示出兩個職責。第一個職責是鏈接管理;第二個職責是數據通訊。

  這兩個職責須要分開嗎?

  這依賴於應用程序變化的方式。若是應用程序的變化會影響到鏈接管理方法的簽名,那麼這個設計就具備僵化性,由於調用send和recv的類必須從新編譯、部署。在這種狀況下,這兩個職責應該被分離,以下圖所示。

  

 

  另外一方面,若是應用程序的變化方式老是致使這兩個職責同時變化,那就沒必要分離它們。

  記住這麼一個結論,僅當變化發生時,變化的軸線才具備實際意義。若是沒有徵兆,那麼應用SRP或者任何其它原則都是不明智的。

5、分離耦合的職責

  請注意,在上圖中,把兩個職責都耦合進了ModemImplementation類中。這也許不是最好的,可是或許必須得這麼作。經常會有一些和硬件或者操做系統的細節有關的緣由,迫使咱們把不肯意耦合在一塊兒的東西耦合在了一塊兒。然而,對於應用的其他部分來講,經過分離它們的接口咱們已經解耦了。

6、持久化

  下圖展現了一種常見的違反SRP的情形。

  

  Employee類包含了業務規則和對於持久化的控制。這個兩個職責在大多數狀況下毫不應該混合在一塊兒。業務規則每每會頻繁地變化,而持久化的方式卻不會如此頻繁的變化,而且變化的緣由也是徹底不一樣的,它們實在兩個方向上變化,一個是業務方向上變化,另外一個是持久化方向上變化。

  把業務規則和持久化子系統綁定在一塊兒的作法是自討苦吃。 測試驅動的開發實踐經常會遠在設計出現臭味以前就迫使咱們分離這兩個職責。然而,若是測試沒有迫使這種分離,那麼就應該使用Facade(外觀)、DAO(數據訪問)或者Proxy(代理)模式對設計進行重構,分離這兩個職責。

7、結論

  SRP是全部原則中最簡單的原則之一,也是最難正確運用的原則之一。咱們會不自覺地把職責結合到一塊兒。軟件設計真正要作的許多工做,就是發現職責並把那些職責相互分離。

相關文章
相關標籤/搜索