## 連載:面向對象葵花寶典:思想、技巧與實踐(30) - SRP原則
前面詳細闡述了“高內聚低耦合”的總體設計原則,但如何讓設計滿足這個原則,并不是一件簡單的事情,幸好各位前輩和大牛已經幫我們歸納總結出來了,這就是“設計原則”和“設計模式”。毫不夸張的說,**只要你吃透這些原則和模式并熟練應用,就能夠做出很好的設計**。
==================================================================
**【SRP原則詳解】**
SRP,single?responsibility?principle,中文翻譯為“單一職責原則”!
?
這是面向對象類設計的第一個原則,也是看起來最簡單的一個原則,但這實際上遠遠沒有那么簡單,很多人都不一定真正理解了!
?
我們隨便找幾個網上的解釋,看看各位大師或者經典網站是如何解釋的:
百度百科([http://baike.baidu.com/view/1545205.htm](http://baike.baidu.com/view/1545205.htm)):
一個類應該有且僅有一個職責。關于職責的含意,面向對象大師Robert.C.Martin有一個著名的定義:所謂一個類的職責是指引起該類變化的原因,如果一個類具有一個以上的職責,那么就會有多個不同的原因引起該類變化,其實就是耦合了多個互不相關的職責,就會降低這個類的內聚性。
說句實話,雖然是面向對象大師Martin的解釋,我還是看得不甚明白:引起類變化的原因太多了,例如:
給類加一個方法是變化吧?
給類加一個屬性是變化吧?
類的函數增加一個參數是變化吧?
。。。。。。
引起這些變化的原因太多了,如果每個原因都是一個職責,那SRP原則簡直就沒法判斷了!
Wiki百科([http://en.wikipedia.org/wiki/Single_responsibility_principle](http://en.wikipedia.org/wiki/Single_responsibility_principle)?)內容和百度百科基本一致,看起來百度百科像wiki百科的翻譯:)
Martin?defines?a?responsibility?as?a?reason?to?change,?and?concludes?that?a?class?or?module?should?have?one,?and?only?one,?reason?to?change.
除了這些標準的解釋外,還有一種說法:SRP就是指每個類只做一件事!
這個解釋更通俗易懂,也更加適合中國人理解。雖然比Martin大師的解釋更清楚一些,但仔細想想,還是有個地方比較難以理解:什么叫做“一件事”?
?
比如說一個學生信息管理類,這個類有“添加學生信息”、“查詢學生信息”、“修改學生信息”、“刪除學生信息”,那么這是4件事情,還是一件事情呢?
?
看起來好像是4個事情,但稍有經驗的朋友應該都知道,這4個事情絕大部分情況下都是一個類來實現的,而不是分成4個類!
?
所以關鍵的問題在于:什么是“一件事”?是每個功能一件事情么??
?
其實答案就在我們自己身上,因為只要我們工作,無時不刻的承擔著一定的“職責”!
現在讓我們拋開面向對象,拋開軟件,拋開計算機,來看看我們自己的“職責”。
?
比如說,我是一個程序猿,我的職責應該是“寫程序”,但寫程序有很多事情,例如:編碼,單元測試、系統測試,bug修復,開會,寫文檔。。。。。。
再比如說,我的BOSS是一個管理者,他的職責是“管理程序猿”,他也有很多工作,例如:制定計劃,團隊建設、開會、協調資源、寫文檔。。。。。。
又比如說,我是一個快遞員,也有很多工作:分包、快遞、收款、開會。。。。。。
?
這些職責其實都不是我們自己定義的,而是公司或者部門或者組織給我們安排工作的時候定義的,也就是說:“職責”是站在他人的角度來定義的,而不是自己定義的,也許你想把自己定義成CEO,但你的老板會真的讓你當CEO么?
?
經過對我們自己的職責的分析,我們可以得出兩個關于職責的重要結論:
1)?職責是站在他人的角度來定義的
2)?職責不是一件事,而是很多事情,但這些事情都是和職責緊密相關的
?
對應到面向對象設計領域,我們可以說一個類的職責應該如下定義:
1)?類的職責是站在其它類的角度來定義的;
2)?類的職責包含多個相關功能;
?
因此,SRP可以翻譯成“**一個類只負責一組相關的事情**”,對應到代碼中就是:一個類有多個方法,這些方法是相關的。
?
當然,如果你再讓我解釋什么是“相關”,那我只能吐血了:)
?
有了這個定義,我們再來看“學生信息管理類”,很明顯,學生管理類具有的4個功能都是和“管理”相關的,按照SRP原則,應該只設計一個“學生信息管理類”就可以了。
?
**【SRP原則范圍】**
但現實世界往往比理想要復雜,一個最典型的例子就是“辦公一體機”。
根據SRP原則,打印機可以設計成一個類,復印機也可以設計成一個類,掃描儀也可以設計成一個類,傳真機還是可以設計成一個類,但偏偏就是出了個“辦公一體機”,這個機器集成了“打印、復印、掃描、傳真”4個職責!
如果我們要設計一個“辦公一體機”的類,怎么也不可能設計出一個符合SRP原則的“辦公一體機”的類來!
?
怎么辦?是SRP不正確么,還是我們永遠都不要設計“辦公一體機”這樣的類?
?
其實SRP也沒有錯,“辦公一體機”也應該設計,但:不要用SRP來約束“辦公一體機”這樣的類!
也就是說,SRP其實是有適應范圍的,SRP只適合那些基礎類,而不適合基于基礎類構建復雜的聚合類。
?
在“辦公一體機“的樣例中,“打印機”、“復印機”、“掃描儀”、“傳真機”都是基礎類,每個類都承擔一個職責,而辦公一體機是“聚合類”,同時集成了4種功能!
?
細心的朋友可能會繼續問道:SRP不能應用于聚合類,那么如何保證聚合類的設計質量呢?
這個問題的答案在GoF的《設計模式》一書中有詳細的答案,即:優先使用對象組合,而不是類繼承。詳細內容請參考后續“設計模式”部分的內容
- 前言
- (1) - 程序設計思想的發展
- (2) - 面向對象語言發展歷史
- (3) - 面向過程 vs 面向對象
- (4) - 面向對象是瑞士軍刀還是一把錘子?
- (5) - 面向對象迷思:面向對象導致性能下降?
- (6) - 不要說你懂“類”
- (7) - “對象”新解
- (8) - “接口” 詳解
- (9) - “抽象類” 詳解
- (10) - “抽象” 詳解
- (11) - “封裝” 詳解
- (12) - “繼承” 詳解
- (13) - “多態” 詳解
- (14) - 面向對象開發技術流程
- (15) - 需求詳解
- (16) - 需求分析終極目的
- (17) - 需求分析518方法
- (18) - 用例分析
- (19) - 功能點提取
- (20) - 用例圖的陷阱
- (21) - SSD
- (22) - 領域模型
- (23) - 領域建模三字經
- (24) - 設計模型
- (25) - 類模型
- (26) - 類模型三板斧
- (27) - 動態模型設計
- (28) - 設計原則:內聚&耦合
- (29) - 高內聚低耦合
- (30) - SRP原則
- (31) - OCP原則
- (32) - LSP原則
- (33) - ISP原則
- (34) - DIP原則
- (35) - NOP原則
- (36) - 設計原則如何用?
- (37) - 設計模式:瑞士軍刀 or 錘子?
- (38) - 設計模式之道
- (39) - 設計原則 vs 設計模式
- (40) - DECORATOR模式
- (完)- 書籍已經出版