“
為什么類的職責(zé)要單一化?
“
類的職責(zé)單一化很容易嗎?
首先,我要提醒一下看到這篇文章的同學(xué),我認(rèn)為保證類(一定是類嗎?)的單一職責(zé)并不容易
軟件開發(fā)過程中,自古就流傳著幾大規(guī)則用戶說模塊,無論如何這里都要和大家闡述一遍
單一職責(zé)原則
一個類應(yīng)該只有一個發(fā)生變化的原因
開閉原則
軟件實體應(yīng)該是可擴(kuò)展,而不可修改的。也就是說,對擴(kuò)展是開放的用戶說模塊,而對修改是封閉的。這個原則是諸多面向?qū)ο缶幊淘瓌t中最抽象、最難理解的一個。
里氏替換原則
所有引用基類的地方必須能透明地使用其子類的對象,換句話說,子類在任何引用基類的地方都可以替換成子類。
依賴倒置原則
這個原則說的詳細(xì)一點其實可以概括為兩點:
高層模塊不應(yīng)該直接依賴于底層模塊,應(yīng)該依賴于抽象抽象不應(yīng)該依賴于具體實現(xiàn),具體實現(xiàn)應(yīng)該依賴于抽象接口隔離原則
程序不依賴于不使用的接口,換句話說,一個程序只依賴于它需要的接口。
單純從概念上講呢,單一職責(zé)原則可算是最簡單易懂的一種原則了,就像設(shè)計模式中的單例模式一樣無趣,是這樣嗎?
誰的職責(zé)
說實話,看過不少講解“職責(zé)單一”設(shè)計原則的文章,都是以類來闡述。其實我覺得不對,職責(zé)單一設(shè)計原則本質(zhì)上是軟件設(shè)計原則的一種思想,具有指導(dǎo)意義。至于誰的職責(zé)需要單一,是一個偽命題,不僅僅指面向?qū)ο缶幊讨械念悾到y(tǒng)的模塊,甚至于微服務(wù)在架構(gòu)設(shè)計中也應(yīng)該遵循此規(guī)則。
在面向?qū)ο笤O(shè)計的理解中,程序最基本的組成單位是類(class),多個類組成模塊(),多個模塊組成服務(wù)(),多個服務(wù)組成系統(tǒng)(),一般的軟件系統(tǒng)都會存在以上幾個概念。
無論是類,還是模塊,還是服務(wù),還是系統(tǒng),我認(rèn)為設(shè)計的時候都要保證“單一職責(zé)”。
單一真的容易嗎
說到“單一”職責(zé),每個人都有不同的看法
class?UserInfo
{
????//用戶id
????public?int?UserId{get?;set?;}
????//用戶登錄賬號
????public?string?Account{get;set?;}
????//用戶登錄密碼
????public?string?Pwd{get?;set;}
????//用戶姓名
????public?string?Name{get?;set?;}
}
以上是最常見的用戶信息實體,你認(rèn)為它職責(zé)單一嗎?說一說,我自己的看法:
站在用戶信息的角度來說,這個類代表的是用戶信息,它就是單一的,這也是大多數(shù)人的看法,有錯嗎?其實沒錯。因為在當(dāng)前場景下,它確實是這樣。
隨著業(yè)務(wù)的發(fā)展,用戶的信息字段會越來越多,比如:用戶的年齡,性別,學(xué)歷....等等。看著越來越大的類,是否該拆分呢?
這個時候我覺得你可以根據(jù)用戶信息的類型來進(jìn)行拆分,畢竟大而全的類其實并不好。怎么拆分呢?比如:可以根據(jù)用戶登錄場景拆分出用戶認(rèn)證的類型
class?UserAuth
{
?????//用戶id
????public?int?UserId{get?;set?;}
????//用戶登錄賬號
????public?string?Account{get;set?;}
????//用戶登錄密碼
????public?string?Pwd{get?;set;}
}
可以根據(jù)用戶信息在系統(tǒng)中的出現(xiàn)頻率和重要度拆分出用戶基本信息和用戶擴(kuò)展信息
class?UserBasicInfo
{
?????//用戶id
????public?int?UserId{get?;set?;}
?????//用戶姓名
????public?string?Name{get?;set?;}
????//用戶手機(jī)號
????public?string?Phone{get?;set?;}
????//其他基本屬性
}
class?UserExtendnfo
{????
?????//用戶郵箱
????public?string?Email{get?;set?;}
????//用戶QQ號
????public?string?QQ{get?;set?;}
????//其他屬性
}
當(dāng)然這里我只是舉個栗子,如果用戶的Email和手機(jī)號一樣常用,可以把Email屬性提到基本屬性中。
以上只是以用戶信息為例,根據(jù)不同的用途進(jìn)行拆分的一個栗子。在不同的業(yè)務(wù)背景下,不同的業(yè)務(wù)階段,對同一個類的拆分可能會有很大不同。有的時候,你所認(rèn)為的"正確“會隨著系統(tǒng)的發(fā)展慢慢變成”錯誤“,當(dāng)然這種”錯誤“并不可怕,畢竟系統(tǒng)的架構(gòu)都是慢慢迭代出來的。
總之呢,評價一個類是否一定滿足單一原則,并沒有一個統(tǒng)一標(biāo)準(zhǔn)和規(guī)范,在實際的開發(fā)中,也沒有必要進(jìn)行過度設(shè)計,在項目初級,完全可以是一個滿足業(yè)務(wù)需求的大而全的類,隨著業(yè)務(wù)的發(fā)展,你必然會經(jīng)歷拆分的過程,這也是軟件發(fā)展的必然階段。
以上只是針對類這個最基本的面向?qū)ο髥挝粊砹牧肆模仙侥K以及系統(tǒng)也是一樣的道理,微服務(wù)也是隨著軟件開發(fā)的不斷演進(jìn)而出現(xiàn)的,其實從職責(zé)上來看,微服務(wù)也是職責(zé)單一原則的產(chǎn)物,而這個這則單一更多的是傾向于業(yè)務(wù)單一性,并非功能單一性。
那職責(zé)拆分的越細(xì)越好嗎?我不這么認(rèn)為,當(dāng)一個類或者模塊甚至系統(tǒng),被拆分過細(xì)的時候,就會面臨著維護(hù)的問題,拿微服務(wù)來說,當(dāng)微服務(wù)的數(shù)量過多,就會面臨著治理等一系列問題,這也是K8s要解決的問題之一。
拆分原則
說到底,雖然職責(zé)單一很難在主觀上給予準(zhǔn)確判斷,但是還是有一些通用規(guī)則可以借鑒,這里以類為例
說到職責(zé)單一,這里順便提一下接口的設(shè)計,接口的設(shè)計更要遵循職責(zé)單一的原則,接口本質(zhì)上是對業(yè)務(wù)的抽象,不同的業(yè)務(wù)應(yīng)該抽象成不同的接口,以保證每個類,每個模塊,每個系統(tǒng)都可以獨立擴(kuò)展。
寫在最后
沒有絕對好的方法可以讓所有人都認(rèn)為你的拆分是正確的“職責(zé)單一”,有的時候,怎么樣才能職責(zé)單一真是要靠“靈感”