對於一個類,應該僅有一個引起它變化的原因,很簡單,如果一個類承擔了多餘一個的職責,那麼引起它變化的原因就會有多個。也就等於把這些職責耦合在了一起。當然了一個職責的變化可能會削弱或者抑制這個類完成其他職責的能力。最終的結果就是這種耦合會導致一種脆弱的設計。例子:Retangle類有兩個方法。一個方法把矩形繪製在表單上,另一個方法計算矩形的面積:
多餘一個的職責的情況
有2個不同的程式使用矩形類,一個是計算幾何學方面的,此時Rectangle類會為次幾何學程式提供協助,它從來是不會在視窗上繪製矩形的。而另一個程式是有關圖形學方面的,他可能也會進行一些幾何學方面的計算,但是它肯定會在視窗上繪製矩形。
所以說這個設計違反了單一職責原則,就是矩形類具有2個職責:1:提供了一個矩形幾何形狀的數學模型;2:把矩形的一個圖形化使用者介面繪製出來。這樣的設計可能會導致一個地方的改動會帶動其他的地方的一列改動。一個比較好的設計是把這兩個職責分離到兩個完全不同的類中。如下:
什麼是職責?
可以理解為:變化的原因,如果你能想到多與一個的動機去改變一個類,那麼這個類就具有多於一個的職責。有時候我們很難做到這一點,都是習慣以組的方式去考慮職責。如下面的介面看起來很合理:該介面所聲明的4個函數確實是數據機所具有的功能:
Interface Modem
{
void dial(string pno);
void hangUp();
void send(string c);
void recv();
}
然而,該介面中卻顯示出兩個職責,第一個職責是串連管理[dial;hangUp];第二個職責是資料通訊[send;recv ],問題是這兩個職責應該被分開嗎?這得依賴於應用程式變化的方式了。如果程式的變化會影響串連函數的簽名,那麼這個設計就具有僵化性的味道。因為send;recv類必須要重新編譯。部署的次數常常會超過我們希望的次數。在這樣的情況下,需要把這兩個職責分離開。但是另一方面,如果應用程式的變化方式總是導致這兩個職責的同時變化,那麼就不必分離他們了。
總結:單一職責是所有原則中最簡單的之一,也是最難正確運用之一。我們會自然的把職責結合在一起,軟體設計真正要做的許多內容,就是發現職責並把那些職責相互分離。