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