深度总结:软件设计七大原则
軟件設(shè)計(jì)七大原則
軟件設(shè)計(jì)原則是設(shè)計(jì)模式的基石。目的只有一個(gè),降低對(duì)象之間的耦合,增加程序的可復(fù)用性、可擴(kuò)展性、可維護(hù)性。
開閉原則 OCP
定義:軟件實(shí)體對(duì)擴(kuò)展開放,對(duì)修改關(guān)閉。
-
對(duì)擴(kuò)展開發(fā),意味著有新的需求或變化時(shí),可以對(duì)現(xiàn)有代碼進(jìn)行擴(kuò)展,以適應(yīng)新的情況。
-
對(duì)修改關(guān)閉,意味著類一旦設(shè)計(jì)完成,就可以獨(dú)立的工作,而不要對(duì)其進(jìn)行任何的修改。
在面向?qū)ο笤O(shè)計(jì)中,我們通常通過繼承和多態(tài)來(lái)實(shí)現(xiàn)OCP,即封裝不變部分。
比如需求要實(shí)現(xiàn)2種狀態(tài)的業(yè)務(wù)。
-
如果用if else來(lái)判斷,那么后面加第三種狀態(tài),就還需要在此接口上增加else邏輯,不符合開閉原則。
-
用策略類實(shí)現(xiàn),則定義策略接口,策略A和策略B為具體實(shí)現(xiàn)類,分別對(duì)應(yīng)兩種狀態(tài)。假如下一次需求要實(shí)現(xiàn)第三種狀態(tài),那么直接定義一個(gè)StrategyC實(shí)現(xiàn)類就可滿足。原有代碼不變,符合開閉原則。
詳情可點(diǎn)擊:策略模式文章
里氏替換原則 LSP
定義:程序中的父類型都可以正確的被子類型替換。
程序中的對(duì)象可以在不改變程序正確性的前提下被它的子類所替換,即子類可以替換任何基類能夠出現(xiàn)的地方,并且經(jīng)過替換后,代碼還能正確工作。
根據(jù)LSP的定義,如果在程序中出現(xiàn)使用instanceof、強(qiáng)制類型轉(zhuǎn)換或者函數(shù)覆蓋,很可能意味著是對(duì)LSP的破壞。
假設(shè)定義一個(gè)抽象禽類,有一個(gè)飛翔方法fly(), 我們就可以自由的繼承禽類衍生出各種鳥兒,并調(diào)用其飛翔方法。如果鴕鳥加入禽類行列,繼承禽類,但不會(huì)飛,那么飛翔方法fly()就顯得多余。而且在所有禽類出現(xiàn)的地方,無(wú)法用鴕鳥替換(此時(shí)不滿足正確業(yè)務(wù)邏輯)。違反了里氏替換原則。
經(jīng)過反思,是設(shè)計(jì)問題,禽類和飛翔無(wú)必然聯(lián)系,所以禽類不應(yīng)該定義飛翔方法fly(),把禽類飛翔方法fly()抽離出去單獨(dú)定義飛翔接口Flyable。
對(duì)于有飛翔能力的鳥兒繼承禽類并實(shí)現(xiàn)飛翔接口。鴕鳥繼承禽類,但不實(shí)現(xiàn)飛翔接口,是否是鳥兒取決于是否繼承自禽類,能不能飛取決于是否實(shí)現(xiàn)飛翔接口。所有禽類出現(xiàn)的地方都可以用子類進(jìn)行替換,所有飛翔接口出現(xiàn)的地方都可以被其替換為實(shí)現(xiàn)。
依賴倒置原則 DIP
定義:模塊之間交互應(yīng)該依賴抽象,而非實(shí)現(xiàn)。
DIP要求高層模塊不應(yīng)該依賴于底層模塊,二者都應(yīng)該依賴于抽象。抽象不應(yīng)該依賴細(xì)節(jié),細(xì)節(jié)應(yīng)該依賴抽象。
比如某個(gè)人喂養(yǎng)小動(dòng)物,如果依賴了具體的實(shí)現(xiàn),則每新增一個(gè)動(dòng)物,需要在Person內(nèi)加一個(gè)對(duì)應(yīng)的方法。違背了開閉原則,也不符合依賴倒置原則。
重新修改后,如下。新增一個(gè)Birds抽象類,具體的動(dòng)物繼承自父類Birds,Person中的方法參數(shù)依賴于抽象,而不是具體的實(shí)現(xiàn)。符合依賴倒置原則。
單一職責(zé)原則 SRP
定義:對(duì)任何類的修改只能有一個(gè)原因。換句話說,一個(gè)類只應(yīng)該負(fù)責(zé)一項(xiàng)職責(zé)。
SRP要求每個(gè)軟件模塊職責(zé)要單一,衡量標(biāo)準(zhǔn)是模塊是否只有一個(gè)被修改的原因。職責(zé)越單一,被修改的原因就越少,模塊的內(nèi)聚性就越高,被復(fù)用的可能性就越大,也更容易被理解。
舉例員工類 Employee,開發(fā)工作變了,需要修改Employee類,測(cè)試工作變了需要修改Employee類,不符合單一職責(zé)原則,類的復(fù)雜性也高。
-
職責(zé)多,引起此類變化的原因也多。后續(xù)變更的風(fēng)險(xiǎn)就大。
-
后續(xù)需求變更,會(huì)造成職責(zé)的混亂,類結(jié)構(gòu)的不穩(wěn)定。
改造后,類的職責(zé)單一。開發(fā)者的職責(zé)就是“寫代碼”,那么對(duì)其進(jìn)行的修改只有與“寫代碼”相關(guān)的一個(gè)原因(畫類圖也是為了指導(dǎo)代碼落地),這樣才能確保類職責(zé)的單一性原則。
同時(shí),類與類之間雖有著明確的職責(zé)劃分,但又一起合作完成任務(wù),它們保持著一種“對(duì)立且統(tǒng)一”的辯證關(guān)系。
-
以責(zé)任鏈模式為例,每個(gè)處理者類職責(zé)清晰,只處理與自己職責(zé)相關(guān)的業(yè)務(wù)。
-
以員工類為例,拆分后,各個(gè)員工完成相應(yīng)的職責(zé),共同保障項(xiàng)目上線。
這種清晰的職責(zé)范圍劃分就是單一職責(zé)原則的最佳實(shí)踐。符合單一職責(zé)原則的設(shè)計(jì)能使類具備高內(nèi)聚性,讓單個(gè)模塊變得簡(jiǎn)單易懂,如此才能增強(qiáng)代碼的可讀性和可復(fù)用性。并提高系統(tǒng)的易維護(hù)性和易測(cè)試性。
上面的例子是類職責(zé)單一,那么微服務(wù)劃分也同理,采用單一職責(zé)原則,每個(gè)服務(wù)負(fù)責(zé)一塊業(yè)務(wù)。同一類業(yè)務(wù)的變更落在單個(gè)服務(wù)內(nèi)變更。
接口隔離原則 ISP
定義:客戶端對(duì)類的依賴基于最小接口,而不依賴不需要的接口。
接口隔離原則認(rèn)為不能強(qiáng)迫用戶去依賴那些他們不使用的接口。換句話說,使用多個(gè)專門的接口比使用單一的總接口要好。做接口拆分時(shí),也要盡量滿足單一職責(zé)原則。將外部依賴減到最少,降低模塊間的耦合。
比如類A只需要使用方法1、方法3,類B只需要使用方法2、方法4,但在源代碼層次上與所有方法形成依賴關(guān)系。這種依賴意味著我們對(duì)接口I的方法2修改,即使不會(huì)影響A所依賴的方法1、方法3的功能,也會(huì)導(dǎo)致它需要重新部署和編譯。
改造后,類A不需要用到方法2、方法4,就可以選擇不依賴它們。代碼更加清晰,接口職責(zé)更加明確。
迪米特法則 LOD
定義:一個(gè)類對(duì)于其它類知道的越少越好。
迪米特法則也被稱為最少知識(shí)原則,它提出一個(gè)模塊對(duì)其他模塊應(yīng)該知之甚少,或者說模塊之間應(yīng)該彼此保持陌生,甚至意識(shí)不到對(duì)方的存在,以此最小化、簡(jiǎn)單化模塊間的通信,并達(dá)到松耦合的目的。
反之,模塊之間若存在過多的關(guān)聯(lián),那么一個(gè)很小的變動(dòng)則可能會(huì)引發(fā)蝴蝶效應(yīng)般的連鎖反應(yīng),最終會(huì)波及大范圍的系統(tǒng)變動(dòng)。我們說,缺乏良好封裝性的系統(tǒng)模塊是違反迪米特法則的,牽一發(fā)動(dòng)全身的設(shè)計(jì)使系統(tǒng)的擴(kuò)展與維護(hù)變的舉步維艱。
門面模式和中介者模式是迪米特法則極好的范例。 Tomcat中 RequestFacade類就使用了外觀模式。RequestFacade是對(duì)Request類封裝,屏蔽內(nèi)部屬性和方法,避免暴露。
合成復(fù)用原則 CRP
定義:優(yōu)先使用合成/聚合,而不是類繼承。
比如對(duì)象的繼承關(guān)系是在編譯時(shí)就定義好了,所以無(wú)法在運(yùn)行時(shí)改變從父類繼承的實(shí)現(xiàn)。子類的實(shí)現(xiàn)與它的父類有非常緊密的依賴關(guān)系,以至于父類實(shí)現(xiàn)中的任何變化必然會(huì)導(dǎo)致子類發(fā)生變化。當(dāng)你需要復(fù)用子類時(shí),如果繼承下來(lái)的實(shí)現(xiàn)不適合解決新的問題,則父類必須重寫或被其它更適合的類替換。這種依賴關(guān)系限制了靈活性并最終限制了復(fù)用性。
合成(組合)和聚合都是關(guān)聯(lián)的特殊種類。
-
聚合表示一種弱的擁有關(guān)系,體現(xiàn)的是A對(duì)象可以包含B對(duì)象,但B對(duì)象不是A對(duì)象的一部分;
-
合成則是一種強(qiáng)大的“擁有”關(guān)系,體現(xiàn)了嚴(yán)格的部分和整體的關(guān)系,部分和整體的生命周期一樣。
合成/聚合復(fù)用原則好處:優(yōu)先使用對(duì)象的合成/聚合將有助于你保持每個(gè)類被封裝,并被集中在單個(gè)任務(wù)上。這樣類和類繼承層次會(huì)保持較小規(guī)模。
舉例:手機(jī)軟件劃分可分為QQ、微信等,按品牌劃分可分為華為、小米等。如果同時(shí)考慮這兩種分類,其組合就很多。往下繼續(xù)擴(kuò)展軟件、手機(jī)品牌,都會(huì)新增許多子類。違背了開閉原則,也限制了復(fù)用性。
用聚合關(guān)系實(shí)現(xiàn)的類圖:后面新增軟件,手機(jī)品牌類不用變更代碼。繼承的層次也少了。
參考資料
劉韜:《秒懂設(shè)計(jì)模式》
張建飛:《代碼精進(jìn)之路:從碼農(nóng)到工匠》
Robert C. Martin:《架構(gòu)整潔之道》
程杰:《大話設(shè)計(jì)模式》
關(guān)注公眾號(hào),后臺(tái)回復(fù)【筆記】獲取技術(shù)筆記PDF。
?
總結(jié)
以上是生活随笔為你收集整理的深度总结:软件设计七大原则的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于VHDL语言的多人表决器的设计
- 下一篇: ISD9160学习笔记08_结项总结