單一原則: 程序設(shè)計(jì)時(shí)功能模塊獨(dú)立,功能單一更有助于維護(hù)和復(fù)用。
例如:個(gè)人計(jì)算機(jī)功能很多,如果想從中只拿出一個(gè)功能來制造一個(gè)新的東西是困難的。同時(shí)如果你的計(jì)算機(jī)開不機(jī),同時(shí)你的計(jì)算器功能也不能用了。
在編程中如果一個(gè)類封裝了太多功能和上面的結(jié)果是類似的。
單一職責(zé)原則
例1:
大家應(yīng)該能看出來這個(gè)類圖中的接口設(shè)計(jì)是有問題的,用戶的屬性和用戶的行為沒有分開。我們根據(jù)用戶的屬性和行為拆開這個(gè)接口。
重新拆分成兩個(gè)接口,IUserBo 負(fù)責(zé)用戶的屬性,IUserBiz負(fù)責(zé)用戶的行為。當(dāng)我們實(shí)例化除UserINfo這個(gè)對象后,我們可以把UserInfo當(dāng)做IUserBo實(shí)現(xiàn)類使用也可以將它當(dāng)做IUserBiz的實(shí)現(xiàn)類使用,這就要看我們用在什么地方了。如果是獲取用戶信息,就把UserInfo 當(dāng)做IUserBOSS的實(shí)現(xiàn)類,如果是維護(hù)用戶信息,就當(dāng)做是IUserBiz的實(shí)現(xiàn)類。在實(shí)際應(yīng)用中我們更傾向于把一個(gè)接口拆分成兩個(gè),一個(gè)是IUserBO一個(gè)是IUserBIz。類圖如下。
這樣做以后,我們就把一個(gè)接口拆成了兩個(gè),這樣就符合了單一職責(zé)原則,那么什么是單一職責(zé)原則呢?
單一職責(zé)原則,核心思想是:一個(gè)類,最好只做一件事,只有一個(gè)引起它變化的原因。
單一職責(zé)原則可以看作是低耦合、高內(nèi)聚在面向?qū)ο笤瓌t上的引申,將職責(zé)定義為引起變化的原因,以提高內(nèi)聚性來減少引起變化的原因。職責(zé)過多,可能引起變化的原因就越多,這將是導(dǎo)致職責(zé)依賴,相互之間就產(chǎn)生影響,從而極大的損傷其內(nèi)聚性和耦合度。單一職責(zé)通常意味著單一的功能,因此不要為類實(shí)現(xiàn)過多的功能點(diǎn),以保證實(shí)體只有一個(gè)引起它變化的原因。例2:
Rectangle擁有兩個(gè)方法,一個(gè)方法是draw,用來畫圖形,另一個(gè)方法是area用來計(jì)算面積。Rectangle違背了單一職責(zé)原則,因?yàn)樗哂袃蓚€(gè)職責(zé):計(jì)算面積與繪制矩形。繪制圖形會與用戶界面有關(guān),但是計(jì)算圖形面積卻未必與界面有關(guān),如果把這兩個(gè)職責(zé)寫到一個(gè)類中,那么如果只需要使用area()方法這一職責(zé)來計(jì)算面積,那就不得不把draw()方法一同編譯,但是卻可能也用不到它。如果其中一個(gè)職責(zé)需要修改,就不得不重新編譯和部署另外一個(gè)。如果類的職責(zé)超過一個(gè),這些職責(zé)之間就會產(chǎn)生耦合。改變一個(gè)職責(zé),可能會影響和妨礙類為其它類服務(wù)的功能。把兩個(gè)職責(zé)分開會好一些。
兩個(gè)職責(zé)分離,這樣耦合度就會降低。SRP原則的核心就是要求對類的改變只能是一個(gè),對于違反這一原則的類應(yīng)該進(jìn)行重構(gòu),例如以Façade模式或Proxy模式分離職責(zé),通過基本的方法Extract Interface、Extract Class和Extract Method進(jìn)行梳理。
例3:看一下下面的接口
public interface Phone
{
//撥通電話
public void dial(string phoneNumber);
//通話
public void chat(object o);
//回應(yīng)
public void answer(object o);
//通話完畢
public void huangup();
}
這個(gè)接口有問題嗎?還真有問題。單一職責(zé)要求一個(gè)接口或者類只有一個(gè)原因引起變化,也就是一個(gè)接口或者類只有一個(gè)職責(zé),它負(fù)責(zé)一件事情。Phone這個(gè)接口不是一個(gè)職責(zé),它是有兩個(gè)職責(zé):一個(gè)是協(xié)議管理,一個(gè)是數(shù)據(jù)傳輸。diag()和huangup()這兩個(gè)方法實(shí)現(xiàn)的是協(xié)議管理,撥號和掛斷。chat()和answer()是數(shù)據(jù)傳輸。協(xié)議改變和數(shù)據(jù)傳輸都會引起類的變化,那么我們就不能說它是符合單一職責(zé)原則。由于這兩個(gè)職責(zé)變化不互相影響,那么就考慮拆成兩個(gè)接口。
這個(gè)類圖已經(jīng)符合單一職責(zé)原則,但是卻復(fù)雜多了,組合是一種強(qiáng)耦合關(guān)系,兩者都有共同的生命期,這種強(qiáng)耦合增加了類的復(fù)雜性,我們修改一下。
這樣設(shè)計(jì)才完美,一個(gè)手機(jī)實(shí)現(xiàn)兩個(gè)接口,把兩個(gè)職責(zé)融合一個(gè)類中,雖然你會覺得這個(gè)phone類有兩個(gè)原因引起變化,但是我們是面向接口編程,對外公布的是接口,而不是實(shí)現(xiàn)類。如果非要使得類符合單一職責(zé)原則,那么就要使用上一個(gè)類圖了,但是這樣的話類的耦合性就增加了.
單一職責(zé)原則的好處:類的復(fù)雜性降低可讀性提高可維護(hù)性提高變更引起的風(fēng)險(xiǎn)降低
您可能感興趣的文章:- C#面向?qū)ο笤O(shè)計(jì)的七大原則
- 淺談C#設(shè)計(jì)模式之開放封閉原則
- 高效C#編碼優(yōu)化原則
- C# 自定義異常總結(jié)及嚴(yán)格遵循幾個(gè)原則
- C# 面向?qū)ο蟮幕驹瓌t
- 淺談C#六大設(shè)計(jì)原則