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