用現實生活中例項解釋說明設計模式六大基本原則

aixueforever 發表於 2021-09-14
設計模式

設計模式分類

  • 建立型模式

    用於描述“怎樣建立物件”,它的主要特點是“將物件的建立與使用分離”。GoF(四人組)書中提供了單例、原型、工廠方法、抽象工廠、建造者等 5 種建立型模式。

  • 結構型模式

    用於描述如何將類或物件按某種佈局組成更大的結構,GoF(四人組)書中提供了代理、介面卡、橋接、裝飾、外觀、享元、組合等 7 種結構型模式。

  • 行為型模式

    用於描述類或物件之間怎樣相互協作共同完成單個物件無法單獨完成的任務,以及怎樣分配職責。GoF(四人組)書中提供了模板方法、策略、命令、職責鏈、狀態、觀察者、中介者、迭代器、訪問者、備忘錄、直譯器等 11 種行為型模式。

軟體設計原則

​ 在軟體開發中,為了提高軟體系統的可維護性和可複用性,增加軟體的可擴充套件性和靈活性,程式設計師要儘量根據6條原則來開發程式,從而提高軟體開發效率、節約軟體開發成本和維護成本。

開閉原則

對擴充套件開放,對修改關閉。在程式需要進行擴充的時候,不能去修改原有的程式碼,實現一個熱插拔的效果。簡言之,是為了使程式的擴充套件性好,易於維護和升級。

想要達到這樣的效果,需要使用介面和抽象類。因為抽象靈活性好,適應性廣,只要抽象的合理,可以基本保持軟體架構的穩定。而軟體中易變的細節可以從抽象派生來的實現類來進行擴充套件,當軟體需要發生變化時,只需要根據需求重新派生一個實現類來擴充套件就可以了。

以部落格園主題為例介紹開閉原則的應用:

使用者可以根據自己的喜愛更換自己的部落格園主題。這些主題有共同的特點,可以為其定義一個抽象類(Theme),而每個具體的主題×××Theme是其子類。使用者可以根據需要選擇或者增加新的主題,而不需要修改原始碼,所以它是滿足開閉原則的。

里氏替換原則

里氏替換原則(The Liskov Substitution Principle,LSP)是由Barbara Liskov女士於1988年提出的,其定義為:“如果對於型別S的每個物件O1存在型別T的物件O2,那麼對於所有定義了T的程式P來說,當用O1替換 O2並且S是T的子型別時,P的行為不會改變”。

里氏代換原則:任何基類可以出現的地方,子類一定可以出現。通俗理解:子類可以擴充套件父類的功能,但不能改變父類原有的功能。換句話說,子類繼承父類時,除新增新的方法完成新增功能外,儘量不要重寫父類的方法。里氏代換原則是對開閉原則的補充,原則上講子類物件介紹給父類物件,也可以說子類替換父類,並且出現在父類能夠出現的任何地方代替父類物件

如果通過重寫父類的方法來完成新的功能,這樣寫起來雖然簡單,但是整個繼承體系的可複用性會比較差,特別是運用多型比較頻繁時,程式執行出錯的概率會非常大。

里氏替換——鴕鳥非鳥

這裡我們以另一個理解里氏替換原則的經典例子“鴕鳥非鳥”來做示例。生物學中對於鳥類的定義是“恆溫動物,卵生,全身披有羽毛,身體呈流線形,有角質的喙,眼在頭的兩側。前肢退化成翼,後肢有鱗狀外皮,有四趾”。從生物學角度來看,鴕鳥肯定是一種鳥,是一種繼承關係。A需求期望鳥類提供與飛翔有關的行為,即使鴕鳥跟普通的鳥在外觀上就是100%的相像,但在A需求範圍內,鴕鳥在飛翔這一點上跟其它普通的鳥是不一致的,它沒有這個能力,所以,鴕鳥類無法從鳥類派生,鴕鳥不是鳥。B需求期望鳥類提供與羽毛有關的行為,那麼鴕鳥在這一點上跟其它普通的鳥一致的。雖然它不會飛,但是這一點不在B需求範圍內,所以,它具備了鳥類全部的行為特徵,鴕鳥類就能夠從鳥類派生,鴕鳥就是鳥。從A來看,鴕鳥和鳥之間的繼承關係又可能不成立。那麼,鴕鳥和鳥之間到底是不是繼承關係如何判斷呢?這需要根據使用者需求來判斷。

如果父類A和子類B之間的關係違反了里氏替換原則,那麼A和B就不適合設計為繼承關係。我們就要重新設計二者之間的關係。設計方案有兩種,需要根據具體情況進行選擇:

  • 建立一個新的抽象類或者介面,作為兩個具體類的基類。將具體類A和B的共同行為轉移到C中,從而解決A和B行為不一致的問題。

  • 將B到A的繼承關係改為委託關係。具體參考組合/聚合複用原則。

依賴倒轉原則

針對介面程式設計,依賴於抽象而不依賴於具體。簡單的說就是要求對抽象進行程式設計,不要對實現進行程式設計,這樣就降低了客戶與實現模組間的耦合。

依賴倒轉——組裝電腦

現要組裝一臺電腦,需要配件cpu,硬碟,記憶體條。只有這些配置都有了,計算機才能正常的執行。選擇cpu有很多選擇,如Intel,AMD等,硬碟可以選擇希捷,西數等,記憶體條可以選擇金士頓,海盜船等。如果組裝的電腦的cpu只能是Intel的,記憶體條只能是金士頓的,硬碟只能是希捷的,這對使用者肯定是不友好的,使用者有了機箱肯定是想按照自己的喜好,選擇自己喜歡的配件。

根據依賴倒轉原則進行改進:我們只需要修改Computer類,讓Computer類依賴抽象(各個配件的介面),而不是依賴於各個元件具體的實現類。

介面隔離原則

使用多個隔離的介面,而非單個介面;一個類對另一個類的依賴應該建立在最小的介面上。

下面看一個例子來理解介面隔離原則

介面隔離——空調

一般空調具有製冷制熱的功能,而有的單冷式空調只有製冷功能,如果只有製冷制熱一個介面,則違背了介面隔離原則。此時應該抽象出製冷制熱兩個介面,而不是隻抽象出製冷制熱這一個介面。

迪米特法則

最少知道原則是指:一個實體應當儘量少地與其他實體之間發生相互作用,使得系統功能模組相對獨立。

只和你的直接朋友交談,不跟“陌生人”說話(Talk only to your immediate friends and not to strangers)。

其含義是:如果兩個實體無須直接通訊,那麼就不應當發生直接的相互呼叫,可以通過第三方轉發該呼叫。其目的是降低類之間的耦合度,提高模組的相對獨立性。

迪米特法則中的“朋友”是指:當前物件本身、當前物件的成員物件、當前物件所建立的物件、當前物件的方法引數等,這些物件同當前物件存在關聯、聚合或組合關係,可以直接訪問這些物件的方法。

迪米特法則——演員與經紀人的關係

演員由於活動繁忙,所以許多日常事務由經紀人負責處理,如和粉絲見面會,安排檔期。這裡的經紀人是明星的朋友,而粉絲和媒體公司是陌生人,所以適合使用迪米特法則。

合成複用原則

合成複用原則是指:儘量先使用組合或者聚合等關聯關係來實現,其次才考慮使用繼承關係來實現。

通常類的複用分為繼承複用和合成複用兩種。

繼承複用雖然有簡單和易實現的優點,但它也存在以下缺點:

  1. 繼承複用破壞了類的封裝性。因為繼承會將父類的實現細節暴露給子類,父類對子類是透明的,所以這種複用又稱為“白箱”複用。
  2. 子類與父類的耦合度高。父類的實現的任何改變都會導致子類的實現發生變化,這不利於類的擴充套件與維護。
  3. 它限制了複用的靈活性。從父類繼承而來的實現是靜態的,在編譯時已經定義,所以在執行時不可能發生變化。

採用組合或聚合複用時,可以將已有物件納入新物件中,使之成為新物件的一部分,新物件可以呼叫已有物件的功能,它有以下優點:

  1. 它維持了類的封裝性。因為成分物件的內部細節是新物件看不見的,所以這種複用又稱為“黑箱”複用。

  2. 物件間的耦合度低。可以在類的成員位置宣告抽象。

  3. 複用的靈活性高。這種複用可以在執行時動態進行,新物件可以動態地引用與成分物件型別相同的物件。

    合成複用原則——網球拍

網球拍有鋁和碳兩種結構,又有多種顏色,如果在抽象類網球拍中同時定義顏色和結構,則會衍生出紅色鋁結構網球拍,藍色鋁結構網球拍,紅色碳結構網球拍,藍色碳結構網球拍等等,我們可以看到使用繼承複用產生了很多子類,如果現在又有新的結構或者新的顏色的話,就需要再定義新的類。我們試著將繼承複用改為聚合複用看一下。可以只在抽象類中保留結構屬性,新建一個顏色介面,讓自類實現不同的顏色介面。