學(xué)習(xí)設(shè)計(jì)模式挣柬,首先要學(xué)習(xí)的就是設(shè)計(jì)原則钥顽。
設(shè)計(jì)原則
1. 單一職責(zé)
簡(jiǎn)單通俗的來(lái)說(shuō):一個(gè)類只負(fù)責(zé)一項(xiàng)職責(zé)。
遵循單一職責(zé)的優(yōu)點(diǎn)有:
可以降低類的復(fù)雜度舞箍,一個(gè)類只負(fù)責(zé)一項(xiàng)職責(zé)舰褪,其邏輯肯定要比負(fù)責(zé)多項(xiàng)職責(zé)簡(jiǎn)單的多;
提高類的可讀性疏橄,提高系統(tǒng)的可維護(hù)性占拍;
變更引起的風(fēng)險(xiǎn)降低略就,變更是必然的,如果單一職責(zé)原則遵守的好晃酒,當(dāng)修改一個(gè)功能時(shí)表牢,可以顯著降低對(duì)其他功能的影響。
2. 里氏替換原則 (Liskov Substitution Principle)
里氏替換原則(Liskov Substitution Principle LSP)面向?qū)ο笤O(shè)計(jì)的基本原則之一贝次。 里氏替換原則中說(shuō)崔兴,任何基類可以出現(xiàn)的地方,子類一定可以出現(xiàn)蛔翅。 LSP是繼承復(fù)用的基石敲茄,只有當(dāng)衍生類可以替換掉基類,軟件單位的功能不受到影響時(shí)搁宾,基類才能真正被復(fù)用折汞,而衍生類也能夠在基類的基礎(chǔ)上增加新的行為。里氏替換原則是對(duì)“開(kāi)-閉”原則的補(bǔ)充盖腿。實(shí)現(xiàn)“開(kāi)-閉”原則的關(guān)鍵步驟就是抽象化爽待。而基類與子類的繼承關(guān)系就是抽象化的具體實(shí)現(xiàn),所以里氏替換原則是對(duì)實(shí)現(xiàn)抽象化的具體步驟的規(guī)范翩腐。
通俗簡(jiǎn)單的說(shuō)就是:子類可以擴(kuò)展父類的功能鸟款,但不能改變父類原有的功能。
再次來(lái)理解里氏替換原則:子類可以擴(kuò)展父類的功能茂卦,但不能改變父類原有的功能何什。
它包含以下4層含義:
子類可以實(shí)現(xiàn)父類的抽象方法,但不能覆蓋父類的非抽象方法等龙。
子類中可以增加自己特有的方法处渣。
當(dāng)子類的方法重載父類的方法時(shí),方法的前置條件(即方法的形參)要比父類方法的輸入?yún)?shù)更寬松蛛砰」拚唬【注意區(qū)分重載和重寫】
當(dāng)子類的方法實(shí)現(xiàn)父類的抽象方法時(shí),方法的后置條件(即方法的返回值)要比父類更嚴(yán)格泥畅。
3. 依賴倒置原則 (Dependence Inversion Principle)
所謂依賴倒置原則(Dependence Inversion Principle)就是要依賴于抽象荠诬,不要依賴于具體。
實(shí)現(xiàn)開(kāi)閉原則的關(guān)鍵是抽象化位仁,并且從抽象化導(dǎo)出具體化實(shí)現(xiàn)柑贞,如果說(shuō)開(kāi)閉原則是面向?qū)ο笤O(shè)計(jì)的目標(biāo)的話,那么依賴倒置原則就是面向?qū)ο笤O(shè)計(jì)的主要手段聂抢。
定義:高層模塊不應(yīng)該依賴低層模塊钧嘶,二者都應(yīng)該依賴其抽象;抽象不應(yīng)該依賴細(xì)節(jié)琳疏;細(xì)節(jié)應(yīng)該依賴抽象康辑。
通俗點(diǎn)說(shuō):要求對(duì)抽象進(jìn)行編程摄欲,不要對(duì)實(shí)現(xiàn)進(jìn)行編程轿亮,這樣就降低了客戶與實(shí)現(xiàn)模塊間的耦合疮薇。
依賴倒置原則基于這樣一個(gè)事實(shí):相對(duì)于細(xì)節(jié)的多變性,抽象的東西要穩(wěn)定的多我注。以抽象為基礎(chǔ)搭建起來(lái)的架構(gòu)比以細(xì)節(jié)為基礎(chǔ)搭建起來(lái)的架構(gòu)要穩(wěn)定的多按咒。在java中,抽象指的是接口或者抽象類
但骨,細(xì)節(jié)就是具體的實(shí)現(xiàn)類
励七,使用接口或者抽象類的目的是制定好規(guī)范和契約,而不去涉及任何具體的操作奔缠,把展現(xiàn)細(xì)節(jié)的任務(wù)交給他們的實(shí)現(xiàn)類去完成掠抬。
依賴倒置原則的核心思想是面向接口編程。
傳遞依賴關(guān)系有三種方式校哎,以上的例子中使用的方法是接口傳遞
两波,另外還有兩種傳遞方式:構(gòu)造方法傳遞
和setter方法傳遞
。
在實(shí)際編程中闷哆,我們一般需要做到如下3點(diǎn):
低層模塊盡量都要有抽象類或接口腰奋,或者兩者都有”д【可能會(huì)被人用到的】
變量的聲明類型盡量是抽象類或接口劣坊。
使用繼承時(shí)遵循里氏替換原則。
依賴倒置原則的核心就是要我們面向接口編程屈留,理解了面向接口編程局冰,也就理解了依賴倒置。
4. 接口隔離原則 (Interface Segregation Principle)
其原則字面的意思是:使用多個(gè)隔離的接口灌危,比使用單個(gè)接口要好康二。本意降低類之間的耦合度,而設(shè)計(jì)模式就是一個(gè)軟件的設(shè)計(jì)思想乍狐,從大型軟件架構(gòu)出發(fā)赠摇,為了升級(jí)和維護(hù)方便。所以上文中多次出現(xiàn):降低依賴浅蚪,降低耦合藕帜。
原定義:客戶端不應(yīng)該依賴它不需要的接口;一個(gè)類對(duì)另一個(gè)類的依賴應(yīng)該建立在最小的接口上惜傲。
接口隔離原則的含義是:建立單一接口洽故,不要建立龐大臃腫的接口,盡量細(xì)化接口盗誊,接口中的方法盡量少时甚。也就是說(shuō)隘弊,我們要為各個(gè)類建立專用的接口,而不要試圖去建立一個(gè)很龐大的接口供所有依賴它的類去調(diào)用荒适。在程序設(shè)計(jì)中梨熙,依賴幾個(gè)專用的接口要比依賴一個(gè)綜合的接口更靈活。接口是設(shè)計(jì)時(shí)對(duì)外部設(shè)定的“契約”刀诬,通過(guò)分散定義多個(gè)接口咽扇,可以預(yù)防外來(lái)變更的擴(kuò)散,提高系統(tǒng)的靈活性和可維護(hù)性陕壹。
說(shuō)到這里质欲,很多人會(huì)覺(jué)的接口隔離原則跟之前的單一職責(zé)原則很相似,其實(shí)不然糠馆。其一嘶伟,單一職責(zé)原則原注重的是職責(zé);而接口隔離原則注重對(duì)接口依賴的隔離又碌。其二九昧,單一職責(zé)原則主要是約束類,其次才是接口和方法赠橙,它針對(duì)的是程序中的實(shí)現(xiàn)和細(xì)節(jié)耽装;而接口隔離原則主要約束接口,主要針對(duì)抽象期揪,針對(duì)程序整體框架的構(gòu)建掉奄。
采用接口隔離原則對(duì)接口進(jìn)行約束時(shí),要注意以下幾點(diǎn):
接口盡量小凤薛,但是要有限度姓建。對(duì)接口進(jìn)行細(xì)化可以提高程序設(shè)計(jì)靈活性是不掙的事實(shí),但是如果過(guò)小缤苫,則會(huì)造成接口數(shù)量過(guò)多速兔,使設(shè)計(jì)復(fù)雜化。所以一定要適度活玲。
為依賴接口的類定制服務(wù)涣狗,只暴露給調(diào)用的類它需要的方法,它不需要的方法則隱藏起來(lái)舒憾。只有專注地為一個(gè)模塊提供定制服務(wù)镀钓,才能建立最小的依賴關(guān)系。
提高內(nèi)聚镀迂,減少對(duì)外交互丁溅。使接口用最少的方法去完成最多的事情。
運(yùn)用接口隔離原則探遵,一定要適度窟赏,接口設(shè)計(jì)的過(guò)大或過(guò)小都不好妓柜。設(shè)計(jì)接口的時(shí)候,只有多花些時(shí)間去思考和籌劃涯穷,才能準(zhǔn)確地實(shí)踐這一原則棍掐。
5. 迪米特法則(最少知道原則) (Demeter Principle)
為什么叫最少知道原則,就是說(shuō):一個(gè)實(shí)體應(yīng)當(dāng)盡量少的與其他實(shí)體之間發(fā)生相互作用求豫,使得系統(tǒng)功能模塊相對(duì)獨(dú)立塌衰。也就是說(shuō)一個(gè)軟件實(shí)體應(yīng)當(dāng)盡可能少的與其他實(shí)體發(fā)生相互作用。這樣蝠嘉,當(dāng)一個(gè)模塊修改時(shí),就會(huì)盡量少的影響其他的模塊杯巨,擴(kuò)展會(huì)相對(duì)容易蚤告,這是對(duì)軟件實(shí)體之間通信的限制,它要求限制軟件實(shí)體之間通信的寬度和深度服爷。
定義:一個(gè)對(duì)象應(yīng)該對(duì)其他對(duì)象保持最少的了解杜恰。
問(wèn)題由來(lái):類與類之間的關(guān)系越密切,耦合度越大仍源,當(dāng)一個(gè)類發(fā)生改變時(shí)心褐,對(duì)另一個(gè)類的影響也越大。
解決方案:盡量降低類與類之間的耦合笼踩。
自從我們接觸編程開(kāi)始逗爹,就知道了軟件編程的總的原則:低耦合,高內(nèi)聚
嚎于。無(wú)論是面向過(guò)程編程還是面向?qū)ο缶幊叹蚨挥惺垢鱾€(gè)模塊之間的耦合盡量的低,才能提高代碼的復(fù)用率于购。低耦合的優(yōu)點(diǎn)不言而喻袍睡,但是怎么樣編程才能做到低耦合呢?那正是迪米特法則要去完成的肋僧。
迪米特法則又叫最少知道原則
斑胜,最早是在1987年由美國(guó)Northeastern University的Ian Holland提出。通俗的來(lái)講嫌吠,就是一個(gè)類對(duì)自己依賴的類知道的越少越好止潘。也就是說(shuō),對(duì)于被依賴的類來(lái)說(shuō)居兆,無(wú)論邏輯多么復(fù)雜覆山,都盡量地的將邏輯封裝在類的內(nèi)部,對(duì)外除了提供的public方法,不對(duì)外泄漏任何信息拦键。迪米特法則還有一個(gè)更簡(jiǎn)單的定義:只與直接的朋友通信千扶。首先來(lái)解釋一下什么是直接的朋友:每個(gè)對(duì)象都會(huì)與其他對(duì)象有耦合關(guān)系汰翠,只要兩個(gè)對(duì)象之間有耦合關(guān)系翎朱,我們就說(shuō)這兩個(gè)對(duì)象之間是朋友關(guān)系侄泽。耦合的方式很多懈贺,依賴犀忱、關(guān)聯(lián)钞它、組合拜银、聚合等。其中遭垛,我們稱出現(xiàn)成員變量尼桶、方法參數(shù)、方法返回值中的類為直接的朋友锯仪,而出現(xiàn)在局部變量中的類則不是直接的朋友泵督。也就是說(shuō),陌生的類最好不要作為局部變量的形式出現(xiàn)在類的內(nèi)部庶喜。
過(guò)分的使用迪米特原則小腊,會(huì)產(chǎn)生大量這樣的中介和傳遞類,導(dǎo)致系統(tǒng)復(fù)雜度變大久窟。所以在采用迪米特法則時(shí)要反復(fù)權(quán)衡秩冈,既做到結(jié)構(gòu)清晰,又要高內(nèi)聚低耦合斥扛。
6. 開(kāi)閉原則(Open Close Principle)
開(kāi)閉原則就是說(shuō)對(duì)擴(kuò)展開(kāi)放入问,對(duì)修改關(guān)閉
。在程序需要進(jìn)行拓展的時(shí)候犹赖,不能去修改原有的代碼队他,實(shí)現(xiàn)一個(gè)熱插拔的效果。所以一句話概括就是:為了使程序的擴(kuò)展性好峻村,易于維護(hù)和升級(jí)麸折。想要達(dá)到這樣的效果,需要面向接口編程粘昨。
定義:一個(gè)軟件實(shí)體如類垢啼、模塊和函數(shù)應(yīng)該對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉张肾。
問(wèn)題由來(lái):在軟件的生命周期內(nèi)芭析,因?yàn)樽兓⑸?jí)和維護(hù)等原因需要對(duì)軟件原有代碼進(jìn)行修改時(shí)吞瞪,可能會(huì)給舊代碼中引入錯(cuò)誤馁启,也可能會(huì)使我們不得不對(duì)整個(gè)功能進(jìn)行重構(gòu),并且需要原有代碼經(jīng)過(guò)重新測(cè)試。
解決方案:當(dāng)軟件需要變化時(shí)惯疙,盡量通過(guò)擴(kuò)展軟件實(shí)體的行為來(lái)實(shí)現(xiàn)變化翠勉,而不是通過(guò)修改已有的代碼來(lái)實(shí)現(xiàn)變化。
開(kāi)閉原則是面向?qū)ο笤O(shè)計(jì)中最基礎(chǔ)的設(shè)計(jì)原則霉颠,它指導(dǎo)我們?nèi)绾谓⒎€(wěn)定靈活的系統(tǒng)对碌。開(kāi)閉原則可能是設(shè)計(jì)模式六項(xiàng)原則中定義最模糊的一個(gè)了,它只告訴我們對(duì)擴(kuò)展開(kāi)放蒿偎,對(duì)修改關(guān)閉朽们,可是到底如何才能做到對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉诉位,并沒(méi)有明確的告訴我們骑脱。以前,如果有人告訴我“你進(jìn)行設(shè)計(jì)的時(shí)候一定要遵守開(kāi)閉原則”不从,我會(huì)覺(jué)的他什么都沒(méi)說(shuō)惜姐,但貌似又什么都說(shuō)了。因?yàn)殚_(kāi)閉原則真的太虛了椿息。
如果仔細(xì)思考以及仔細(xì)閱讀很多設(shè)計(jì)模式的文章后,會(huì)發(fā)現(xiàn)其實(shí)坷衍,我們遵循設(shè)計(jì)模式前面5大原則寝优,以及使用23種設(shè)計(jì)模式的目的就是遵循開(kāi)閉原則。也就是說(shuō)枫耳,只要我們對(duì)前面5項(xiàng)原則遵守的好了乏矾,設(shè)計(jì)出的軟件自然是符合開(kāi)閉原則的,這個(gè)開(kāi)閉原則更像是前面五項(xiàng)原則遵守程度的“平均得分”迁杨,前面5項(xiàng)原則遵守的好钻心,平均分自然就高,說(shuō)明軟件設(shè)計(jì)開(kāi)閉原則遵守的好铅协;如果前面5項(xiàng)原則遵守的不好捷沸,則說(shuō)明開(kāi)閉原則遵守的不好。
開(kāi)閉原則無(wú)非就是想表達(dá)這樣一層意思:用抽象構(gòu)建框架狐史,用實(shí)現(xiàn)擴(kuò)展細(xì)節(jié)
痒给。因?yàn)槌橄箪`活性好,適應(yīng)性廣骏全,只要抽象的合理苍柏,可以基本保持軟件架構(gòu)的穩(wěn)定。而軟件中易變的細(xì)節(jié)姜贡,我們用從抽象派生的實(shí)現(xiàn)類來(lái)進(jìn)行擴(kuò)展试吁,當(dāng)軟件需要發(fā)生變化時(shí),我們只需要根據(jù)需求重新派生一個(gè)實(shí)現(xiàn)類來(lái)擴(kuò)展就可以了楼咳。當(dāng)然前提是我們的抽象要合理熄捍,要對(duì)需求的變更有前瞻性和預(yù)見(jiàn)性才行烛恤。
說(shuō)到這里,再回想一下前面說(shuō)的5項(xiàng)原則治唤,恰恰是告訴我們用抽象構(gòu)建框架棒动,用實(shí)現(xiàn)擴(kuò)展細(xì)節(jié)的注意事項(xiàng)而已:?jiǎn)我宦氊?zé)原則告訴我們實(shí)現(xiàn)類要職責(zé)單一;里氏替換原則告訴我們不要破壞繼承體系宾添;依賴倒置原則告訴我們要面向接口編程船惨;接口隔離原則告訴我們?cè)谠O(shè)計(jì)接口的時(shí)候要精簡(jiǎn)單一;迪米特法則告訴我們要降低耦合缕陕。而開(kāi)閉原則是總綱粱锐,他告訴我們要對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉扛邑。