【正文】
這些職責(zé)耦合在一起,當(dāng)其中一個(gè)職責(zé)變化時(shí),可能會(huì)影響其他職責(zé)的運(yùn)作。 ? 單一職責(zé)原則是實(shí)現(xiàn) 高內(nèi)聚、低耦合 的指導(dǎo)方針,在很多代碼重構(gòu)手法中都能找到它的存在,它是最簡(jiǎn)單但又最難運(yùn)用的原則,需要設(shè)計(jì)人員發(fā)現(xiàn)類的不同職責(zé)并將其分離,而發(fā)現(xiàn)類的多重職責(zé)需要設(shè)計(jì)人員具有較強(qiáng)的分析設(shè)計(jì)能力和相關(guān)重構(gòu)經(jīng)驗(yàn)。這里類包括兩個(gè)職責(zé),顯然違反了SRP。 ? 因此要重構(gòu) Modem類,從中抽象出兩個(gè)接口,一個(gè)專門負(fù)責(zé)連接,另一個(gè)專門負(fù)責(zé)數(shù)據(jù)傳送。如下圖: 單一職責(zé)原則 ?這樣以來(lái),無(wú)論單獨(dú)修改連接部分還是單獨(dú)修改數(shù)據(jù)傳送部分,都彼此互不影響。 單一職責(zé)原則 ?單一職責(zé)原則實(shí)例 ? 實(shí)例解析 開(kāi)閉原則 ?開(kāi)閉原則定義 ?開(kāi)閉原則 (OpenClosed Principle, OCP)定義如下: ? 一個(gè)軟件實(shí)體應(yīng)當(dāng) 對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉 。 ?其英文定義為: ? Software entities should be open for extension, but closed for modification. 開(kāi)閉原則 ?開(kāi)放封閉原則是所有面向?qū)ο笤瓌t的核心。 ? 開(kāi)放封閉原則主要體現(xiàn)在兩個(gè)方面: 對(duì)擴(kuò)展開(kāi)放,意味著有新的需求或變化時(shí),可以對(duì)現(xiàn)有代碼進(jìn)行擴(kuò)展,以適應(yīng)新的情況。 開(kāi)閉原則 ?為什么要用到開(kāi)放封閉原則呢? ?軟件需求總是變化的,世界上沒(méi)有一個(gè)軟件的是不變的,因此對(duì)軟件設(shè)計(jì)人員來(lái)說(shuō),必須在不需要對(duì)原有系統(tǒng)進(jìn)行修改的情況下,實(shí)現(xiàn)靈活的系統(tǒng)擴(kuò)展。讓類依賴于固定的抽象,所以對(duì)修改就是封閉的;而通過(guò)面向?qū)ο蟮睦^承和多態(tài)機(jī)制,可以實(shí)現(xiàn)對(duì)抽象體的繼承,通過(guò)覆寫其方法來(lái)改變固有行為,實(shí)現(xiàn)新的擴(kuò)展方法,所以對(duì)于擴(kuò)展就是開(kāi)放的。 L o g i n F o r m b u t t o n : C i r c l e B u t t o n+ d i s p l a y ( ) : v o i dC i r c l e B u t t o n+ v i e w ( ) : v o i dL o g i n F o r m b u t t o n : R e c t a n g l e B u t t o n+ d i s p l a y ( ) : v o i dR e c t a n g l e B u t t o n+ v i e w ( ) : v o i d開(kāi)閉原則 ?開(kāi)閉原則實(shí)例 ?實(shí)例解析 ... ... AbstractButton {abstract} + view () ... : void LoginForm button : AbstractButton + display () ... : void CircleButton + view () : void RectangleButton + view () : void 里氏代換原則 ? 里氏代換原則定義 ? 里氏代換原則 (Liskov Substitution Principle, LSP)有兩種定義方式,第一種定義方式相對(duì)嚴(yán)格,其定義如下: ? 如果對(duì)每一個(gè)類型為 S的對(duì)象 o1,都有類型為 T的對(duì)象 o2,使得以 T定義的所有程序 P在所有的對(duì)象 o1都代換成 o2時(shí),程序 P的行為沒(méi)有變化,那么類型 S是類型 T的子類型。 ? 其英文定義為: ? Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it. 里氏代換原則 ?里氏代換原則分析 ?里氏代換原則可以通俗表述為:在 軟件中如果能夠使用基類對(duì)象,那么一定能夠使用其子類對(duì)象 。 ?里氏代換原則是實(shí)現(xiàn)開(kāi)閉原則的重要方式之一,由于使用基類對(duì)象的地方都可以使用子類對(duì)象,因此 在程序中盡量使用基類類型來(lái)對(duì)對(duì)象進(jìn)行定義,而在運(yùn)行時(shí)再確定其子類類型,用子類對(duì)象來(lái)替換父類對(duì)象 。注意在類中調(diào)用其他類時(shí)務(wù)必調(diào)用父類,如果不能調(diào)用父類,說(shuō)明類的射擊已經(jīng)違反了 LSP原則。為了解決這個(gè)問(wèn)題, ToyGun可以脫離繼承,建立一個(gè)獨(dú)立的父類,為了做到代碼可以復(fù)用,可以與 AbstractGun建立關(guān)聯(lián)關(guān)系,如下圖: 里氏代換原則 ? 因此,如果子類不能完整地實(shí)現(xiàn)父類的方法,那么建議斷開(kāi)父子繼承關(guān)系,采用依賴,聚合,組合等關(guān)系代替繼承。 里氏代換原則 ?里氏代換原則實(shí)例 ?實(shí)例說(shuō)明 ? 某系統(tǒng)需要實(shí)現(xiàn)對(duì)重要數(shù)據(jù)(如用戶密碼)的加密處理,在數(shù)據(jù)操作類 (DataOperator)中需要調(diào)用加密類中定義的加密算法,系統(tǒng)提供了兩個(gè)不同的加密類, CipherA和 CipherB,它們實(shí)現(xiàn)不同的加密方法,在DataOperator中可以選擇其中的一個(gè)實(shí)現(xiàn)加密操作。 ? 現(xiàn)使用里氏代換原則對(duì)其進(jìn)行重構(gòu),使得系統(tǒng)可以靈活擴(kuò)展,符合開(kāi)閉原則。 抽象不應(yīng)該依賴于細(xì)節(jié),細(xì)節(jié)應(yīng)該依賴于抽象。 ? 其英文定義為: ? Program to an interface, not an implementation. 依賴倒轉(zhuǎn)原則 ?依賴倒轉(zhuǎn)原則分析 ?簡(jiǎn)單來(lái)說(shuō),依賴倒轉(zhuǎn)原則就是指: 代碼要依賴于抽象的類,而不要依賴于具體的類 ; 要針對(duì)接口或抽象類編程,而不是針對(duì)具體類編程 。 依賴倒轉(zhuǎn)原則 ?依賴倒轉(zhuǎn)原則分析 ?類之間的耦合 ? 零耦合 關(guān)系 ? 具體耦合 關(guān)系 ? 抽象耦合 關(guān)系 ?依賴倒轉(zhuǎn)原則要求客戶端依賴于抽象耦合, 以抽象方式耦合是依賴倒轉(zhuǎn)原則的關(guān)鍵 。 ? 面向?qū)ο蟮拈_(kāi)發(fā)很好的解決了這個(gè)問(wèn)題,一般的情況下抽象的變化概率很小,讓用戶程序依賴于抽象,實(shí)現(xiàn)的細(xì)節(jié)也依賴于抽象。這大大降低了客戶程序域?qū)崿F(xiàn)細(xì)節(jié)的耦合度。面向過(guò)程的結(jié)構(gòu)圖: 依賴倒轉(zhuǎn)原則 ? 但是如何現(xiàn)在公司業(yè)務(wù)規(guī)模擴(kuò)大了,該自動(dòng)駕駛系統(tǒng)還要把吉普車也兼容了。 ? 但是軟件是不斷變化的,軟件的需求也是變化的,如果將來(lái)業(yè)務(wù)又?jǐn)U大了,該自動(dòng)駕駛系統(tǒng)還有能實(shí)現(xiàn)通用、三菱、大眾汽車,這樣我們不得不又要修改 AutoSystem類了。 依賴倒轉(zhuǎn)原則 ? 導(dǎo)致上面所述問(wèn)題一個(gè)原因是,含有高層策略的模塊,如 Au