1. 程式人生 > >如何定義一個類——單一職責原則

如何定義一個類——單一職責原則

就是 應該 系統 本質 獨立 ice 地方 tasks 很多

單一職責原則:就一個類而言,應該僅有一個引起他變化的原因。

1 一個老師類的例子

或者說在外部看來,一個類只應該能看到它的類的相關功能。如老師類只應該負責教授知識,備課,但是不應該負責開車。
技術分享圖片
切合實際的說一個TaskService類不應該包含處理時間的類,他可以是private的,但是肯定不能是public的。
這裏引出另一個角度

2 如何看待一個類?

2.1通常的看法

通常的看法是,類是由成員屬性和成語方法組成的數據結構
技術分享圖片
或者是現實事物的抽象
如對現實中的人抽象出Person,他具備人的基本屬性和基本行為
技術分享圖片

2.2另外一個角度

但是另外一個角度來看,類是一組職責的集合。類負責他所代表的抽象的職責。
如老師類,就是上課,下課,教書,備課等職責的集合,他對外提供這些接口。姓名年齡這些通常是private封裝的。

技術分享圖片
舉日常開發的例子
如任務類,就是查看任務,發布任務,撤回任務,處理任務,完成任務,關閉任務等職責集合。
虛線表示依賴關系,可以認為是使用關系,任務服務類依賴於任務實體類。
技術分享圖片
如果這裏面有個時間處理的方法,那麽這個方法肯定是不應該對外public的,如果這個方法比較獨立的話,可以封裝在日期類中,再通過依賴引入進來。
技術分享圖片

3 高內聚低耦合

提到單一職責的時候經常提到高內聚低耦合。
內聚性是 類中操作之間聯系的緊密程度。
低內聚就是很多功能互不相關,比如時間處理功能和上課功能,就是風馬牛不相及的兩個功能。高內聚就是聯系緊密。
耦合性是 類之間聯系的緊密程度。
或者說依賴程度。低耦合就是互相之間的依賴小。
低耦合,首先所有類都負責自己的職責,不同職責由不同類去維護,所以類與類之間的耦合是低的

高內聚,一系列職責由單個類去維護,所有相似的職責內聚在一個類中,這個就是高內聚
一類職責應該集中在一個類中,而不是分散在不同的類中,而不同的職責應該準確劃分到不同的類中。
高內聚低耦合的一個反面例子是我在維護的一個老項目。。
一個功能的幾個部分被分在了不同的地方,sql在jsp上能看到,沒有控制層,一個方法纏纏繞繞出現在了多個類中,而且這個劃分的幾個部分大多數是沒有復用性的。

我們常說有的框架重,讓開發者的類和框架類耦合在了一起,開發者的類必須繼承框架的某個基類,一旦基類進行了版本升級,那麽可能對整個系統都造成影響。

問答部分

Q 我有一個任務類,它有一個發布任務和撤回任務,他是不是單一職責的
A:是的,這兩個都屬於任務類的職責。

Q 單一職責是僅有一個引起類變化的原因,這裏發布任務和撤回任務有變動的話類不是都要變動嗎
A:原因是指一系列職責。
Q 如果任務類裏包含了一個對外開放的時間處理接口,這個任務類是單一職責嗎
A:不是,時間不屬於任務處理系列的職責,他應該被設置成private或者放到DateUtil中。
Q 任務處理類中定義時間接口有什麽壞處嗎
A:

  • 首先時間處理不屬於任務處理類的職責
  • 其次時間處理處理接口放在任務處理類中,正常情況下不會把所有時間處理的接口都放在任務處理類裏,那麽時間處理的職責就分散在了不同的類中,違反了高內聚;由於時間處理接口分布在不同的類中,這些類的職責耦合在了一起,違反了低耦合
  • 當第三方調用任務處理類的時候會不明所以,為什麽這裏會有一個時間接口,不確定這個方法能不能調用,後期會不會有改動。
  • 一旦時間接口改動,要考慮到是否影響到任務類中的其他接口,需要考慮很多,而如果內聚在時間處理類中,相對影響要小。
    如果用任務處理類和時間接口做例子比較不明顯,我們換下面這個例子就立馬可以發現問題了,他們本質是一個問題,只是錯誤程度不同:
    在老師類中定義一個清除系統緩存的接口

如何定義一個類——單一職責原則