1. 程式人生 > >設計模式的7原則及23種設計模式概要

設計模式的7原則及23種設計模式概要

一、設計模式的原則

1.開放封閉原則

        開放封閉原則(OCP,Open Closed Principle)是所有面向物件原則的核心。軟體設計本身所追求的目標就是封裝變化、降低耦合,而開放封閉原則正是對這一目標的最

直接體現。其他的設計原則,很多時候是為實現這一目標服務的,例如以Liskov替換原則實現最佳的、正確的繼承層次,就能保證不會違反開放封閉原則。

        關於開放封閉原則,其核心的思想是:

        軟體實體應該是可擴充套件,而不可修改的。也就是說,對擴充套件是開放的,而對修改是封閉的。

        因此,開放封閉原則主要體現在兩個方面:

        1.對擴充套件開放,意味著有新的需求或變化時,可以對現有程式碼進行擴充套件,以適應新的情況。

        2.對修改封閉,意味著類一旦設計完成,就可以獨立完成其工作,而不要對類進行任何修改。

        “需求總是變化”、“世界上沒有一個軟體是不變的”,這些言論是對軟體需求最經典的表白。從中透射出一個關鍵的意思就是,對於軟體設計者來說,必須在不需要對原有系

統進行修改的情況下,實現靈活的系統擴充套件。而如何能做到這一點呢?

         只有依賴於抽象。實現開放封閉的核心思想就是對抽象程式設計,而不對具體程式設計,因為抽象相對穩定。讓類依賴於固定的抽象,所以對修改就是封閉的;而通過面向物件的

繼承和對多型機制,可以實現對抽象體的繼承,通過覆寫其方法來改變固有行為,實現新的擴充套件方法,所以對於擴充套件就是開放的。這是實施開放封閉原則的基本思路,同時這種

機制是建立在兩個基本的設計原則的基礎上,這就是Liskov替換原則和合成/聚合複用原則。對於違反這一原則的類,必須進行重構來改善,常用於實現的設計模式主要有

Template Method模式和Strategy模式。而封裝變化,是實現這一原則的重要手段,將經常發生變化的狀態封裝為一個類。

2.依賴倒置原則

A.高層次的模組不應該依賴於低層次的模組,他們都應該依賴於抽象。

B.抽象不應該依賴於具體實現,具體實現應該依賴於抽象。

         依賴倒置原則(Dependence Inversion Principle)是程式要依賴於抽象介面,不要依賴於具體實現。簡單的說就是要求對抽象進行程式設計,不要對實現進行程式設計,這樣就降

低了客戶與實現模組間的耦合。面向過程的開發,上層呼叫下層,上層依賴於下層,當下層劇烈變動時上層也要跟著變動,這就會導致模組的複用性降低而且大大提高了開發的

成本。面向物件的開發很好的解決了這個問題,一般情況下抽象的變化概率很小,讓使用者程式依賴於抽象,實現的細節也依賴於抽象。即使實現細節不斷變動,只要抽象不變

客戶程式就不需要變化。這大大降低了客戶程式與實現細節的耦合度。

3.迪米特法則

         迪米特法則可以簡單說成:talk only to your immediate friends。 對於OOD來說,又被解釋為下面幾種方式:一個軟體實體應當儘可能少的與其他實體發生相互作用。每

一個軟體單位對其他的單位都只有最少的知識,而且侷限於那些與本單位密切相關的軟體單位。

         迪米特法則的初衷在於降低類之間的耦合。由於每個類儘量減少對其他類的依賴,因此,很容易使得系統的功能模組功能獨立,相互之間不存在(或很少有)依賴關係。

迪米特法則不希望類之間建立直接的聯絡。如果真的有需要建立聯絡,也希望能通過它的友元類來轉達。因此,應用迪米特法則有可能造成的一個後果就是:系統中存在大量的

中介類,這些類之所以存在完全是為了傳遞類之間的相互呼叫關係——這在一定程度上增加了系統的複雜度。有興趣可以研究一下設計模式的門面模式(Facade)和中介模式

(Mediator),都是迪米特法則應用的例子。

4.單一職責原則

        所謂職責是指類變化的原因。如果一個類有多於一個的動機被改變,那麼這個類就具有多於一個的職責。而單一職責原則就是指一個類或者模組應該有且只有一個改變的原

因。一個類,只有一個引起它變化的原因。應該只有一個職責。每一個職責都是變化的一個軸線,如果一個類有一個以上的職責,這些職責就耦合在了一起。這會導致脆弱的設

計。當一個職責發生變化時,可能會影響其它的職責。另外,多個職責耦合在一起,會影響複用性。例如:要實現邏輯和介面的分離。

         之所以會出現單一職責原則就是因為在軟體設計時會出現以下類似場景:負責兩個不同的職責:職責P1,職責P2。當由於職責P1需求發生改變而需要修改類T時,有可能

會導致原本執行正常的職責P2功能發生故障。也就是說職責P1和P2被耦合在了一起。

5.介面隔離原則

        使用場合,提供呼叫者需要的方法,遮蔽不需要的方法.滿足介面隔離原則.比如說電子商務的系統,有訂單這個類,有三個地方會使用到,一個是門戶,只能有查詢方法,一個是外部

系統,有新增訂單的方法,一個是管理後臺,新增刪除修改查詢都要用到.根據介面隔離原則(ISP),一個類對另外一個類的依賴性應當是建立在最小的介面上.也就是說,對於門戶,它只

能依賴有一個查詢方法的介面.


6.優先原則(優先使用組合而不是繼承)

         面向物件系統中功能複用的兩種最常用技術是類繼承和物件組合(object composition)。正如我們已解釋過的,類繼承允許你根據其他類的實現來定義一個類的實現。這種

通過生成子類的複用通常被稱為白箱複用(white-box reuse)。術語“白箱”是相對可視性而言:在繼承方式中,父類的內部細節對子類可見。物件組合是類繼承之外的另一種複用

選擇。新的更復雜的功能可以通過組裝或組合物件來獲得。物件組合要求被組合的物件具有良好定義的介面。這種複用風格被稱為黑箱複用(black-box reuse),因為物件的內部

細節是不可見的。物件只以“黑箱”的形式出現。

        繼承和組合各有優缺點。類繼承是在編譯時刻靜態定義的,且可直接使用,因為程式設計語言直接支援類繼承。類繼承可以較方便地改變被複用的實現。當一個子類重定義

一些而不是全部操作時,它也能影響它所繼承的操作,只要在這些操作中呼叫了被重定義的操作。

        但是類繼承也有一些不足之處。首先,因為繼承在編譯時刻就定義了,所以無法在執行時刻改變從父類繼承的實現。更糟的是,父類通常至少定義了部分子類的具體表示。因為繼承對子類揭示了其父類的實現細節,所以繼承常被認為“破壞了封裝性” 。子類中的實現與它的父類有如此緊密的依賴關係,以至於父類實現中的任何變化必然會導

致子類發生變化。當你需要複用子類時,實現上的依賴性就會產生一些問題。如果繼承下來的實現不適合解決新的問題,則父類必須重寫或被其他更適合的類替換。這種依賴關

系限制了靈活性並最終限制了複用性。一個可用的解決方法就是隻繼承抽象類,因為抽象類通常提供較少的實現。

        物件組合是通過獲得對其他物件的引用而在執行時刻動態定義的。組合要求物件遵守彼此的介面約定,進而要求更仔細地定義介面,而這些介面並不妨礙你將一個物件和其

他物件一起使用。這還會產生良好的結果:因為物件只能通過介面訪問,所以我們並不破壞封裝性;只要型別一致,執行時刻還可以用一個物件來替代另一個物件;更進一步,

因為物件的實現是基於介面寫的,所以實現上存在較少的依賴關係。物件組合對系統設計還有另一個作用,即優先使用物件組合有助於你保持每個類被封裝,並被集中在單個任

務上。這樣類和類繼承層次會保持較小規模,並且不太可能增長為不可控制的龐然大物。另一方面,基於物件組合的設計會有更多的物件 (而有較少的類),且系統的行為將依賴

於物件間的關係而不是被定義在某個類中。這匯出了我們的面向物件設計的第二個原則:優先使用物件組合,而不是類繼承。       

7.里氏替換原則

二、23種設計模式

1.建立型模式:用來處理物件的建立過程

(2)工廠模式(Factory Pattern)

(3)抽象工廠模式(Factory Pattern)

(4)建造者模式(Builder Pattern)

2.結構型模式:用來處理類和物件的組合

3.行為型模式:用來對類或物件怎麼進行互動和怎樣分配職責進行描述

(20)訪問者模式(Visitor Pattern)