徹底弄懂類設計原則之 – 單一職責原則

類設計原則之 – 單一職責

類的設計原則之單一職責原則,是最常用的類的設計的原則之一

英文: SRP , Simple Responsibility Principle

中文:單一職責原則

這是面向對象類設計中的第一個原則 ,也是看起來最簡單的一個原則,但是實際上遠遠沒有這麼簡單,很多人不一定真正理解了!

類設計,通俗的講不是怎麼去寫一個類更好,應該遵循什麼樣的原則設計類更好。

我們隨便找幾個網上的解釋:看看各位大師或者經典網站是怎麼解釋的。

百度百科:就一個類而言,應該僅有一個引起它變化的原因。應該只有一個職責。

說句實在話,我最開始也是對這句話似懂非懂,看的不是太明白,因為,引起一個類變化 的原因太多了,比如

  • 給類增加一個方法是變化吧?
  • 給類增加一個屬性是變化吧?
  • 給類的方法增加一個函數是變化吧?
  • ……

引起這些變化的原因太多了,如果每個原因都是一個職責,那麼SRP簡直就無法判斷了!

維基百科:(內容基本上和百度百科一致),通俗的講就是:一個類只做一件事

這個解釋更通俗易懂,也更符合中國人的理解。但是仔細想想,還是有幾個地方比較難理解:

什麼叫做 「一件事」 ?

舉個例子:

比如有一個學生管理類,這個類有 添加學生資訊 , 修改學生資訊 查詢學生資訊刪除學生資訊

問題來了, 這是 4 件事 ? 還是 1 件事 ?

看起來好像是 4 件事, 但是稍有經驗的人都知道,這 4 件事都是由一個類來實現的,而不是設計 4 個類!

所以問題的關鍵在於:什麼是 「一件事」 ? 是每個功能一件事嗎?

其實答案就在我們自己身上, 因為只要我們工作,就無時無刻的在承擔著一定的職責

現在拋開面向對象,拋開軟體,拋開電腦,來看看我們自己的職責

  1. 比如我是一個程式設計師,我的職責是寫程式 , 但 寫程式 有很多事情,例如 編碼單元測試系統測試bug修復開會寫文檔
  2. 比如我的老闆是一個管理者,他的職責是 管理程式設計師 ,他也有很多工作,例如 制訂計劃 , 團隊建設開會 ,協調 績效考評
  3. 比如我是一個快遞員,我的職責是送快遞,但是我也有很多事要做,例如 分包 , 快遞 ,收款 , 開會

這些職責都不是我們自己定義的,而是公司或者部門或者組織,給我們安排工作的時候定義的。

也就是說,職責 是站在他人的角度上定義的,而不是我們自己定義的。

經過我們對職責 定義的分析,我們可以得出 2 個關於職責的重要結論

  • 職責是站在他人的角度上定義的
  • 職責不是一件事,而是很多事,但這些事都是和職責緊密結合的。

對應到面向對象設計領域,我們可以說一個類的職責應該如下定義:

  • 類的職責是站在其它類的角度來定義的
  • 類的職責包含多個相關功能

因此,SRP 可以翻譯為 一個類只負責一組相關的事 , 對應到程式碼中就是:一個類有多個方法,這些方法是相關的

有了這個定義,我們再來看看學生資訊管理類, 很明顯,它具有的 4 個功能都是和 管理 相關的,按照 SRP 應該只設計一個學生資訊管理類就可以了。

歡迎關注我們的 HelloWorld開發者社區, www.helloworld.net ,很好記的域名哦

SRP 的應用範圍

但是現實世界往往比理想更複雜,一個最典型的例子就是 辦公一體化

根據 SRP , 印表機可以設計成一個類,複印機可以設計成一個類,掃描儀可以設計成一個類,傳真機也可以設計成一個類

但偏偏就出了一個 辦公一體化 , 這個機器集成了 列印複印掃描 , 傳真 4 個職責 !

如果我們設計一個 辦公一體化 的類,怎麼也不可能設計出一個符合 SRP 的 辦公一體化的類

怎麼辦? 是 SRP 不正確 ? 還是我們永遠都不要設計一個 辦公一體化 的類 ?

其實 SRP 沒有錯, 辦公一體化 也應該設計, 但是不要用 SRP 原則來約束 辦公一體化 這樣的類!

也就是說, SRP 其實是有適用範圍的, SRP 只適合那些基礎類,而不適合基於基礎類構建複雜類的聚合類

辦公一體化 的樣例中, 印表機 ,複印機 , 掃描儀傳真機 都是基礎類,每個類都承擔一個職責

辦公一體化 是一個聚合類, 同時集成了4種功能!

細心的你可能發現了:SRP不能應用於聚合類, 那麼如何保證聚合類的設計品質呢?

換句話說,遇到這樣的情況,如何設計這樣的聚合類呢?

這個問題在 GoF 的 《設計模式》 一書中有詳細的答案,即優先使用對象組合 ,而不是類繼承。

類的單一原則就到這裡了,現小結一下:

  • 類的單一原則(SRP):一個類只負責一組相關的事, 對應到程式碼中就是:一個類有多個方法,這些方法是相關的
  • 職責是站在他人的角度上定義的
  • 類的職責包含多個相關功能
  • SRP 只適合那些基礎類,而不適合基於基礎類構建複雜類的聚合類
  • 對於複雜的聚合類,優先使用組合 ,而不是繼承
  • 最後一條,歡迎關注我們的HelloWorld開發者社區 , 網址:www.helloworld.net ,域名很好記哦

歡迎關注我們的下一篇文章,出講解更多的類設計的原則。