面向对象六大原则——单一职责原则
什么是單一職責原則(Single Responsibility Principle, SRP)
?在講解什么是單一職責原則之前,我們先說一個例子,吊一下口味:我們在做項目的時候,會接觸到用戶,機構,角色管理這些模塊,基本上使用的都是RBAC模型(Role-Based Access Control,基于角色的訪問控制, 通過分配和取消角色來完成用戶權限的授予和取消,使動作主體(用戶)與資源的行為(權限)分離)。現在假設這樣一種場景,我們把用戶管理,修改用戶信息,增加機構,增加角色等維護信息寫到一個接口中進行管理,類圖如下:
分析上面的類圖我們會發現,這樣的設計是非常不合理的,用戶的屬性和用戶的行為是兩種不同的業務模式,把它們都寫在一個類中顯然不行。我們應該把用戶的信息抽取成一個BO(Business Object, 業務對象), 把行為抽取成一個Biz(Business Logic, 業務邏輯), 重新設計的類圖如下:
SRP在類或接口中的使用
?SRP的原話是:There should never be more than one reason for a class to change.翻譯過來其實也很好懂:應該有且僅有一個原因引起類的變更。看下面的例子:
/** 上面的的類圖對應的接口入下 */ public interface IPhone{//撥通電話public void dial(String phoneNumber);//通話public void chat(Object o);//掛斷電話public void hangup(); }在看到這個接口的時候,我們都會認為這樣的設計是沒有問題的,撥通電話,通話,掛斷電話寫在同一個接口里面并沒有什么錯。但是,我們仔細分析,這個接口真的沒有問題嗎?單一職責原則要求一個接口或類只有一個原因引起變化,也就是說一個接口或一個類只有一個原則,它就只負責一件事。 但我們分析上面這個接口,卻發現它包含了兩個職責:一個時協議管理,一個是數據傳送。dial()和hangup()兩個方法實現的是協議管理,分別是撥通電話和掛機。chat()實現的是數據傳送,把我們說的話轉換成模擬信號或數字信號傳遞給對方,然后再把對方傳遞過來的信號還原成我們聽得懂的語言。這里的協議接通和數據傳送的變化都會引起該接口或實現類的變化。我們想一想,這兩個職責會相互影響嗎?不管是什么協議,協議接通只負責將電話接通就行,而數據傳輸只需要傳輸數據,不必要去管協議是如何接通的。所以通過分析,IPhone接口包含了兩個職責,而且這兩個職責的變化不互相影響,這就可以考慮分成兩個接口,類圖如下:
觀察上面的類圖,我們發現這樣的設計會比原來籠統的設計優雅的多,現在的設計在職責上比原來更加分明,讓人一眼就能看出這個接口負責的是什么。也許有人會問,Phone這個類實現了兩個接口,又把兩個職責融合在了一個類中,那么是不是就有兩個原因引起了它的變化了呢?別忘了,我們是面向接口編程,我們對外公布的是接口(API),并非實現類,給你提供了模板,在接口層面已經為你明確了職責,那么具體的實現怎么弄就需要開發者去考慮了。
SRP也適用于方法
?其實,單一職責原則不僅適用于類,接口,同樣適用于方法中。這要舉一個例子了,比如我們做項目的時候會遇到修改用戶信息這樣的功能模塊,我們一般的想法是將用戶的所有數據都接收過來,比如用戶名,信息,密碼,家庭地址等等,然后統一封裝到一個User對象中提交到數據庫,我們一般都是這么干的,就如下面這樣:
?其實這樣的方法是不可取的,因為職責不明確,方法不明確,你到底是要修改密碼,還是修改用戶名,還是修改地址,還是都要修改?這樣職責不明確的話在與其他項目成員溝通的時候會產生很多麻煩,正確的設計如下:
SRP的優點
- 類的復雜性降低,對于實現什么職責都有清晰明確的定義。
- 可讀性提高。
- 可維護性提高。
- 變更引起的風險降低,一個接口的修改只對相應的實現類有影響,對其他接口無影響,這對系統的擴展性,維護性都有非常大的幫助。
參考書籍
- 《設計模式之禪》
總結
以上是生活随笔為你收集整理的面向对象六大原则——单一职责原则的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 观察者模式Observer
- 下一篇: 理解zookeeper选举机制