一、面向?qū)ο笤O(shè)計七大原則
單一職責(zé)原則(Single Responsibility Principle)
每一個類應(yīng)該專注于做一件事情浪默。里氏替換原則(Liskov Substitution Principle)
超類存在的地方赶舆,子類是可以替換的龄坪。依賴倒置原則(Dependence Inversion Principle)
實現(xiàn)盡量依賴抽象叙身,不依賴具體實現(xiàn)。接口隔離原則(Interface Segregation Principle)
應(yīng)當(dāng)為客戶端提供盡可能小的單獨的接口志鹃,而不是提供大的總的接口夭问。迪米特法則(Law Of Demeter)
又叫最少知識原則,一個軟件實體應(yīng)當(dāng)盡可能少的與其他實體發(fā)生相互作用曹铃。開閉原則(Open Close Principle)
面向擴(kuò)展開放缰趋,面向修改關(guān)閉。組合/聚合復(fù)用原則(Composite/Aggregate Reuse Principle CARP)
盡量使用合成/聚合達(dá)到復(fù)用陕见,盡量少用繼承秘血。原則: 一個類中有另一個類的對象。
二评甜、細(xì)則
1) 單一職責(zé)原則(Single Responsibility Principle)
- 因為:
可以降低類的復(fù)雜度灰粮,一個類只負(fù)責(zé)一項職責(zé),其邏輯肯定要比負(fù)責(zé)多項職責(zé)簡單的多忍坷;提高類的可讀性粘舟,提高系統(tǒng)的可維護(hù)性;變更引起的風(fēng)險降低佩研,變更是必然的蓖乘,如果單一職責(zé)原則遵守的好,當(dāng)修改一個功能時韧骗,可以顯著降低對其他功能的影響嘉抒。需要說明的一點是單一職責(zé)原則不只是面向?qū)ο缶幊趟枷胨赜械模灰悄K化的程序設(shè)計袍暴,都適用單一職責(zé)原則些侍。 - 所以:
從大局上看Android中的Paint和Canvas等類都遵守單一職責(zé)原則,Paint和Canvas各司其職政模。
2)里氏替換原則(Liskov Substitution Principle)
- 因為:
里氏替換原則告訴我們岗宣,在軟件中將一個基類對象替換成它的子類對象,程序?qū)⒉粫a(chǎn)生任何錯誤和異常淋样,反過來則不成立耗式,如果一個軟件實體使用的是一個子類對象的話,那么它不一定能夠使用基類對象趁猴。里氏替換原則是實現(xiàn)開閉原則的重要方式之一刊咳,由于使用基類對象的地方都可以使用子類對象,因此在程序中盡量使用基類類型來對對象進(jìn)行定義儡司,而在運行時再確定其子類類型娱挨,用子類對象來替換父類對象。 - 所以:
使用里氏替換原則時需要注意捕犬,子類的所有方法必須在父類中聲明跷坝,或子類必須實現(xiàn)父類中聲明的所有方法酵镜。盡量把父類設(shè)計為抽象類或者接口,讓子類繼承父類或?qū)崿F(xiàn)父接口柴钻,并實現(xiàn)在父類中聲明的方法淮韭,運行時,子類實例替換父類實例贴届,我們可以很方便地擴(kuò)展系統(tǒng)的功能缸濒,同時無須修改原有子類的代碼,增加新的功能可以通過增加一個新的子類來實現(xiàn)粱腻。
從大局看Java的多態(tài)就屬于這個原則。
3)依賴倒置原則(Dependence Inversion Principle)
- 因為:
具體依賴抽象斩跌,上層依賴下層绍些。假設(shè)B是較A低的模塊,但B需要使用到A的功能耀鸦,這個時候柬批,B不應(yīng)當(dāng)直接使用A中的具體類;而應(yīng)當(dāng)由B定義一抽象接口袖订,并由A來實現(xiàn)這個抽象接口氮帐,B只使用這個抽象接口;這樣就達(dá)到了依賴倒置的目的洛姑,B也解除了對A的依賴上沐,反過來是A依賴于B定義的抽象接口。通過上層模塊難以避免依賴下層模塊楞艾,假如B也直接依賴A的實現(xiàn)参咙,那么就可能造成循環(huán)依賴。 - 所以:
采用依賴倒置原則可以減少類間的耦合性硫眯,提高系統(tǒng)的穩(wěn)定性蕴侧,減少并行開發(fā)引起的風(fēng)險,提高代碼的可讀性和可維護(hù)性两入。
從大局看Java的多態(tài)就屬于這個原則净宵。
4)接口隔離原則(Interface Segregation Principle)
- 因為:
提供盡可能小的單獨接口,而不要提供大的總接口裹纳。暴露行為讓后面的實現(xiàn)類知道的越少越好择葡。譬如類ProgramMonkey通過接口CodeInterface依賴類CodeC,類ProgramMaster通過接口CodeInterface依賴類CodeAndroid剃氧,如果接口CodeInterface對于類ProgramMonkey和類CodeC來說不是最小接口刁岸,則類CodeC和類CodeAndroid必須去實現(xiàn)他們不需要的方法。將臃腫的接口CodeInterface拆分為獨立的幾個接口她我,類ProgramMonkey和類ProgramMaster分別與他們需要的接口建立依賴關(guān)系虹曙。也就是采用接口隔離原則迫横。 - 所以:
建立單一接口,不要建立龐大的接口酝碳,盡量細(xì)化接口矾踱,接口中的方法盡量少。也就是要為各個類建立專用的接口疏哗,而不要試圖去建立一個很龐大的接口供所有依賴它的類去調(diào)用呛讲。依賴幾個專用的接口要比依賴一個綜合的接口更靈活。接口是設(shè)計時對外部設(shè)定的約定返奉,通過分散定義多個接口贝搁,可以預(yù)防外來變更的擴(kuò)散,提高系統(tǒng)的靈活性和可維護(hù)性芽偏。
從大局來說Java的接口可以實現(xiàn)多繼承就是接口隔離原則的基礎(chǔ)保障雷逆。
5)迪米特法則(Law Of Demeter)
- 因為:
類與類之間的關(guān)系越密切,耦合度也就越來越大污尉,只有盡量降低類與類之間的耦合才符合設(shè)計模式膀哲;對于被依賴的類來說,無論邏輯多復(fù)雜都要盡量封裝在類的內(nèi)部被碗;每個對象都會與其他對象有耦合關(guān)系某宪,我們稱出現(xiàn)成員變量、方法參數(shù)锐朴、方法返回值中的類為直接的耦合依賴兴喂,而出現(xiàn)在局部變量中的類則不是直接耦合依賴,也就是說焚志,不是直接耦合依賴的類最好不要作為局部變量的形式出現(xiàn)在類的內(nèi)部瞻想。 - 所以:
一個對象對另一個對象知道的越少越好,即一個軟件實體應(yīng)當(dāng)盡可能少的與其他實體發(fā)生相互作用娩嚼,在一個類里能少用多少其他類就少用多少蘑险,尤其是局部變量的依賴類,能省略盡量省略岳悟。同時如果兩個類不必彼此直接通信佃迄,那么這兩個類就不應(yīng)當(dāng)發(fā)生直接的相互作用。如果其中一個類需要調(diào)用另一個類的某一方法的話贵少,可以通過第三者轉(zhuǎn)發(fā)這個調(diào)用呵俏。
從大局來說Android App開發(fā)中的多Fragment與依賴的Activity間交互通信遵守了這一法則。
6)開閉原則(Open Close Principle)
- 因為:
開放封閉原則主要體現(xiàn)在對擴(kuò)展開放滔灶、對修改封閉普碎,意味著有新的需求或變化時,可以對現(xiàn)有代碼進(jìn)行擴(kuò)展录平,以適應(yīng)新的情況麻车。軟件需求總是變化的缀皱,世界上沒有一個軟件的是不變的,因此對軟件設(shè)計人員來說动猬,必須在不需要對原有系統(tǒng)進(jìn)行修改的情況下啤斗,實現(xiàn)靈活的系統(tǒng)擴(kuò)展。 - 所以:
可以通過Template Method模式和Strategy模式進(jìn)行重構(gòu)赁咙,實現(xiàn)對修改封閉钮莲,對擴(kuò)展開放的設(shè)計思路。
封裝變化彼水,是實現(xiàn)開放封閉原則的重要手段崔拥,對于經(jīng)常發(fā)生變化的狀態(tài),一般將其封裝為一個抽象凤覆,拒絕濫用抽象链瓦,只將經(jīng)常變化的部分進(jìn)行抽象。
7)組合/聚合復(fù)用原則(Composite/Aggregate Reuse Principle CARP)
- 因為:
其實整個設(shè)計模式就是在講如何類與類之間的組合/聚合叛赚。在一個新的對象里面通過關(guān)聯(lián)關(guān)系(包括組合關(guān)系和聚合關(guān)系)使用一些已有的對象,使之成為新對象的一部分稽揭,新對象通過委派調(diào)用已有對象的方法達(dá)到復(fù)用其已有功能的目的俺附。也就是,要盡量使用類的合成復(fù)用溪掀,盡量不要使用繼承事镣。
如果為了復(fù)用,便使用繼承的方式將兩個不相干的類聯(lián)系在一起揪胃,違反里氏代換原則璃哟,哪是生搬硬套,忽略了繼承了缺點喊递。繼承復(fù)用破壞數(shù)據(jù)封裝性随闪,將基類的實現(xiàn)細(xì)節(jié)全部暴露給了派生類,基類的內(nèi)部細(xì)節(jié)常常對派生類是透明的骚勘,白箱復(fù)用铐伴;雖然簡單,但不安全俏讹,不能在程序的運行過程中隨便改變当宴;基類的實現(xiàn)發(fā)生了改變,派生類的實現(xiàn)也不得不改變泽疆;從基類繼承而來的派生類是靜態(tài)的户矢,不可能在運行時間內(nèi)發(fā)生改變,因此沒有足夠的靈活性殉疼。 - 所以:
組合/聚合復(fù)用原則可以使系統(tǒng)更加靈活梯浪,類與類之間的耦合度降低捌年,一個類的變化對其他類造成的影響相對較少,因此一般首選使用組合/聚合來實現(xiàn)復(fù)用驱证;其次才考慮繼承延窜,在使用繼承時,需要嚴(yán)格遵循里氏代換原則抹锄,有效使用繼承會有助于對問題的理解逆瑞,降低復(fù)雜度,而濫用繼承反而會增加系統(tǒng)構(gòu)建和維護(hù)的難度以及系統(tǒng)的復(fù)雜度伙单,因此需要慎重使用繼承復(fù)用获高。