二十三種設計模式修煉手冊


不知不覺,在開發這條道路上摸爬打滾也有些年頭了,偶爾回頭看看之前寫的代碼,真可謂粗糙至極。固然了,那時候仍是小白,代碼寫得難看些情有可原,不過如今可不能再用之前的標準去衡量本身了,所以掌握一些高級架構技巧是必須的,設計模式正是一個很好的敲門磚。html

在我看來,設計模式不只僅只是一套模板,要想掌握設計模式並作到觸類旁通,必須深刻理解其中的思想,這個模式是爲了解決什麼問題?解決的思路是什麼?代碼的實現又如何?若是問題細節發生了微小的變化又該如何處理?因此說思考很重要,不能死記硬背,必定要多想。算法

寫下這篇文章,是爲了梳理本身的知識點,作個記錄。若是有來人看到了,而且對你有幫助的話,我也會很開心,由於知識是要傳播的,你們都樂於分享本身的看法,才能共同進步。編程


設計模式的定義

模式一詞起源於建築業,描述瞭解決問題的核心方法。經過這種方式,能夠屢次重用那些已有的解決方案,無須重複相同的工做。設計模式

模式能夠應用於不一樣的領域,軟件模式是將模式的通常概念應用於軟件開發領域,能夠被認爲是對軟件開發中某一特定問題的解法的某種統一表示。軟件模式並不是僅限於設計模式,還包括架構模式、分析模式和過程模式等,在軟件生存期的每個階段都存在着一些被認同的模式。架構

在軟件模式領域,目前研究最深刻的是設計模式。設計模式是一套被反覆使用、多數人知曉的、通過分類編目的、代碼設計經驗的總結,使用這些設計模式是爲了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。函數


設計模式的基本要素

設計模式通常有以下幾個基本要素:模式名稱、問題、目的、解決方案、效果、實例代碼和其餘相關設計模式,其中的關鍵元素包括如下四個方面:學習

模式名稱:經過一兩個詞來描述模式的問題、解決方案和效果,以更好地理解模式並方便開發人員之間的交流。this

問題:描述了應該在什麼時候使用模式,它包含了設計中存在的問題以及問題存在的緣由。有時候問題描述可能會包含使用該模式時必須知足的一系列先決條件。spa

解決方案:描述了設計模式的組成部分,以及這些組成部分之間的相互關係,各自職責和協做方式。解決方案並不描述一個特定而具體的設計或實現,而是提供設計問題的抽象描述和怎樣用一個具備通常意義的元素組合(類或者對象)來解決這個問題。設計

效果:描述模式應有的效果以及在使用模式時應權衡的問題。效果主要包含模式的優缺點分析,所以須要綜合考慮模式的效果。


設計模式的分類

設計模式通常有兩種分類方式,一種是根據目的分類(模式是用來作什麼的),另外一種則是根據範圍分類(模式是用來處理類之間的關係仍是處理對象之間的關係)。根據這兩種分類分別有以下兩張表供參考:


範圍\目的 建立型模式 結構型模式 行爲型模式
類模式 工廠方法模式 (類)適配器模式 解釋器模式
模板方法模式
對象模式 抽象工廠模式
建造者模式
原型模式
單例模式
(對象)適配器模式
橋接模式
組合模式
裝飾模式
外觀模式
享元模式
代理模式
職責鏈模式
命令模式
迭代器模式
中介者模式
備忘錄模式
觀察者模式
狀態模式
策略模式
訪問者模式

下面簡單對二十三種設計模式進行說明


模式類別 模式名稱 模式說明
建立型模式
抽象工廠模式 提供了一個建立一系列相關或相互依賴對象的接口,而無須指定它們具體的類
工廠方法模式 該類的實例化操做延遲到子類中完成,即由子類來決定究竟該實例化(建立)哪個類
建造者模式 將一個複雜對象的構建與它的表示分離,使得一樣的構建過程能夠建立不一樣的表示
原型模式 經過給出一個原型對象來指明要建立對象的類型,而後經過複製這個原型對象來建立更多同類型的對象
單例模式 確保在系統中某一個類只有一個實例,能夠自行實例化並向整個系統提供這個實例
結構型模式
適配器模式 將一個接口轉換成客戶但願的另外一個接口,從而使接口不兼容的那些類能夠一塊兒工做
橋接模式 將抽象部分與它的實現部分分離,使它們均可以獨立地變化
組合模式 組合多個對象造成樹形結構以表示「總體-部分」的結構層次
裝飾模式 動態地給一個對象增長一些額外的職責
外觀模式 爲複雜子系統提供一個一致的接口
享元模式 經過運用共享技術有效地支持大量細粒度對象的複用
代理模式 給某一個對象提供一個引用,並由代理對象控制對原對象的引用
結構型模式
職責鏈模式 避免請求發送者與接收者耦合在一塊兒,讓多個對象都有可能接收請求,將這些對象鏈接成一條鏈,而且沿着這條鏈傳遞請求,直到有對象處理爲止
職責鏈模式 避免請求發送者與接收者耦合在一塊兒,讓多個對象都有可能接收請求,將這些對象鏈接成一條鏈,而且沿着這條鏈傳遞請求,直到有對象處理爲止
命令模式 將一個請求封裝爲一個對象,從而使得請求調用者和請求接收者解耦
解釋器模式 描述如何爲語言定義一個語法,如何在該語言中表示一個句子,以及如何解釋這些句子
迭代器模式 提供了一種方法來訪問聚合對象,而不用暴露這個對象的內部表示
中介者模式 經過一箇中介對象來封裝一系列的對象交互,使得各對象不須要顯式地相互引用,從而使其耦合鬆散,並且能夠獨立地改變它們之間的交互
備忘錄模式 在不破壞封裝的前提下,捕獲一個對象的內部狀態,並在該對象以外保存這個狀態,這樣能夠在之後將對象恢復到原先保存的狀態
觀察者模式 定義了對象間的一種一對多依賴關係,使得當每個對象狀態發生改變時,其相關依賴對象皆獲得通知並被自動更新
狀態模式 容許將一個對象在其內部狀態改變時改變它的行爲
策略模式 定義一系列算法,並將每個算法封裝在一個類中,讓它們能夠相互替換,策略模式讓算法獨立於使用它的客戶而變化
模板方法模式 定義一個操做中算法的骨架,而將一些步驟延遲到子類中
訪問者模式 表示將一個做用於某對象結構中的各元素操做,它使得用戶能夠在不改變各元素的類的前提下定義做用於這些元素的新操做

軟件設計模式修煉 -- 簡單工廠模式
軟件設計模式修煉 -- 工廠方法模式
軟件設計模式修煉 -- 抽象工廠模式
軟件設計模式修煉 -- 建造者模式
軟件設計模式修煉 -- 原型模式
軟件設計模式修煉 -- 單例模式
軟件設計模式修煉 -- 適配器模式
軟件設計模式修煉 -- 橋接模式
軟件設計模式修煉 -- 組合模式
軟件設計模式修煉 -- 裝飾模式
軟件設計模式修煉 -- 外觀模式
軟件設計模式修煉 -- 享元模式
軟件設計模式修煉 -- 代理模式
軟件設計模式修煉 -- 職責鏈模式
軟件設計模式修煉 -- 命令模式
軟件設計模式修煉 -- 解釋器模式
軟件設計模式修煉 -- 迭代器模式
軟件設計模式修煉 -- 中介者模式
軟件設計模式修煉 -- 備忘錄模式
軟件設計模式修煉 -- 觀察者模式
軟件設計模式修煉 -- 狀態模式
軟件設計模式修煉 -- 策略模式
軟件設計模式修煉 -- 模板方法模式
軟件設計模式修煉 -- 訪問者模式


以上就是設計模式的簡單介紹,下面是一些補充知識,若是已經掌握了能夠不看。這些知識雖然不屬於設計模式範疇,但對於咱們理解設計模式有莫大的好處。


統一建模語言

統一建模語言(UML)是一種可視化的標準建模語言,經過UML能夠構造軟件系統的藍圖。在設計模式中,使用UML來分析和設計每個模式的結構,描述每個模式實例,幫助咱們深刻理解設計模式。

好比要蓋一棟房子,須要先設計圖紙,設計圖紙就是一種設計語言,也就是模型語言。在一個現代化工程中,人們要溝通和協做,就必須使用標準的工業化設計語言,經過建模進行描述,把所要設計的結構和系統的行爲聯繫起來,對系統的結構進行可視化控制。


UML 結構

UML 是由圖形符號表達的建模語言,其主要包括如下幾個部分:

視圖

使用不一樣的視圖從不一樣角度來描述軟件系統,包括:

用戶視圖:以用戶觀點表示系統的目標,它是全部視圖的核心,該視圖描述系統的需求

結構視圖:表示系統的靜態行爲和靜態元素,如包、類與對象,以及它們之間的關係

行爲視圖:表示系統的動態行爲,描述組成元素如對象在系統運行時的交互關係

實現視圖:表示系統中邏輯元素的分佈,描述系統中物理文件以及它們之間的關係

環境視圖:表示系統中物理元素的分佈,描述系統中硬件設備以及它們之間的關係

提供了十三種與上述五種視圖相對。在設計模式的學習中,重點關注類圖、順序圖和狀態圖便可。

用例圖:對應用戶視圖。在用例圖中,使用用例來表示系統的功能需求,用例圖表示多個外部執行者與系統用例之間以及用例與用例之間的關係。

類圖:對應於結構視圖。類圖使用類來描述系統的靜態結構,類圖包括類和它們之間的關係。

對象圖:對應於結構視圖。對象圖用於表示類的對象實例之間的關係。

包圖:對應於結構視圖。描述包與包之間的關係。

組合結構圖:對應於結構視圖。表示一個類的內部結構。

狀態圖:對應於行爲視圖。描述一系列對象的狀態及狀態之間的轉換。

活動圖:對應於行爲視圖。表示系統中各類活動的次序。

順序圖:又稱時序圖或序列圖,對應於行爲視圖。表示對交互,重點表示對象之間發送消息的時間順序。

定時圖:對應於行爲視圖。定時圖採用一種帶數字刻度的時間軸來描述消息的順序,相比順序圖來講更加精確。

交互概覽圖:對應於行爲視圖。能夠把交互概覽圖理解爲細化的活動圖,在其中的活動都經過一些小型的順序圖來表示。

組件圖:又稱構件圖,對應於實現視圖。描述每一個功能所在組件位置以及它們之間的位置。

部署圖:又稱實施圖,對應於環境視圖。描述軟件中各個組件駐留的硬件位置以及這些硬件之間的交互關係。

模型元素

模型元素包括事物以及事物之間的聯繫。事物表明任何能夠定義的東西,事物之間的關係把事物聯繫在一塊兒,組成有意義的結構模式

通訊機制

爲模型元素提供額外的註釋、修飾和語義。


面向對象設計原則

面向對象設計原則是學習設計模式的基礎,每一種設計模式都符合某一種或多種面向對象設計原則。在軟件開發中使用這些原則能夠提升軟件的可維護性和可複用性,讓咱們能夠設計出更加靈活也更容易擴展的軟件設計,實現可維護性複用的目標。

單一職責原則

一個對象應該只包含單一的職責,而且該職責被完整地封裝在一個類中

一個類承擔的職責越多,被複用的可能性越小,而且至關於將這些職責耦合在一塊兒。所以須要將這些職責進行分離,實現高內聚、低耦合的指導方針。

開閉原則

一個軟件實體應當對擴展開放,對修改關閉。也就是說在設計一個模塊,應當使這個模塊能夠在不被修改的前提下被擴展。

在開閉原則的定義中,軟件實體能夠是一個軟件模塊、一個由多個類組成的局部結構或一個類。

軟件的需求會隨着時間推移發生變化,若是軟件設計符合開閉原則,就能夠在擴展時無須修改現有代碼,保證穩定性與延續性。

抽象化是知足開閉原則的關鍵,經過定義一個相對穩定的抽象層,將不一樣的實現行爲在具體實現層中實現。若是須要修改,無須改動抽象層,只需增長新的實體類來實現新的業務功能便可。

里氏代換原則

全部引用基類(父類)的地方必須能透明地使用其子類的對象。說白了就是:在軟件中若是能使用其基類對象,那麼必定能使用其子類對象。把基類都替換成它的子類,程序不會產生任何錯誤。但反過來則不成立,若是一個軟件實體使用的是一個子類,那麼它不必定能使用基類。

里氏代換原則是實現開閉原則的重要方式之一,在程序中儘可能使用基類類型來定義對象,而在運行時再肯定其子類類型,用子類對象來替代父類對象。

依賴倒轉原則

高層模塊不該該依賴低層模塊,它們都應該依賴抽象。抽象不該該依賴於細節,細節應該依賴於抽象。即代碼要依賴於抽象的類,而不依賴於具體的類,要針對接口編程,不要針對實現編程。

若是說開閉原則是面向對象設計的目標的話,那麼依賴倒轉原則就是面向對象設計的主要手段。下面介紹依賴倒轉原則中常常提到的兩個概念。

類之間的耦合:在面向對象系統中,兩個類之間一般能夠發生三種不一樣的耦合關係(依賴關係)

1. 零耦合關係:兩個類之間沒有任何耦合關係
 2. 具體耦合關係:兩個具體類之間存在一個類對另外一個具體類實例的直接引用
 3. 抽象耦合關係:發生在一個具體類和抽象類之間,也能夠發生在兩個抽象類之間。依賴倒轉原則要求客戶端依賴於抽象耦合。

依賴注入:簡單來講,依賴注入就是將一個類的對象傳入另外一個類,注入時應該注入父類對象,而在程序運行時再經過子類對象來覆蓋父類對象。依賴注入有三種方式

1. 構造注入:經過構造函數注入實例變量
 2. 設值注入:經過Setter方法注入實例變量
 3. 接口注入:經過接口方法注入實例變量

接口隔離原則

一旦一個接口太大,則須要將它分割成一些更小的接口,使用該接口的客戶端僅需知道與之相關的方法便可。

這裏的接口每每有兩種不一樣的含義:

一種是指一個類型所具備的方法的特徵的集合,僅僅是邏輯上的概念,接口的劃分將直接帶來類型的劃分。此時能夠把接口理解成角色,一個接口只表明一個角色,每一個角色都有它特有的一個接口,此時這個原則叫作角色隔離原則。

另外一種是指接口僅僅提升客戶端須要的行爲,即所需的方法。接口應該儘可能細化,接口中的方法進來少,每一個接口只包含一個客戶端所需的角色。

合成複用原則

儘可能使用組合對象,而不是繼承來達到複用的目的。通俗來講,合成複用原則就是指一個新的對象裏經過關聯關係(包括組合關係和聚合關係)來使用一些已有對象,使之成爲新對象的一部分;新對象經過委派調用已有對象的方法達到複用已有功能的目的。

經過繼承來實現複用很簡單,子類能夠覆蓋父類方法,易於擴展。但會破壞系統的封裝性,由於繼承會將基類的實現細節暴露給子類,這種複用又稱爲「白箱複用」。

經過組合/聚合來複用是將一個類的對象做爲另外一個類的對象的一部分。新對象能夠調用已有對象的功能,這種複用又稱爲「黑箱複用」。

迪米特法則

指一個軟件實體應儘量少的與其餘實體發生相互做用。當一個模塊修改時,就會盡可能少的影響其餘模塊,這是對軟件實體之間通訊的限制,它要求軟件實體之間通訊的寬度和深度。

在迪米特法則中,對於一個對象,其朋友包括如下幾類:

當前對象自己(this)

以參數形式傳入到當前對象方法中的對象

當前對象的成員對象

若是當前對象的成員對象是一個集合,那麼集合中的元素也都是朋友

當前對象所建立的對象

任何對象若是知足上面的條件之一,就是當前對象的「朋友」,不然就是「陌生人」。

狹義的迪米特法則:若是兩個類之間沒必要彼此通訊,那麼這兩個類就不該當發生直接的相互做用。若是其中一個類須要調用另外一個類的某一個方法的話,能夠經過第三者轉發這個調用。狹義的迪米特法則能夠下降類之間的耦合,但也會形成系統不一樣模塊之間通訊效率下降,使得系統的不一樣模塊之間不容易協調。

廣義的迪米特法則:指對象之間的信息流量、流向以及信息的影響的控制,主要是對信息隱藏的控制。信息的隱藏可使各個子系統之間脫耦,每個模塊不依賴於其餘模塊存在,所以每個模塊均可以獨立地在其餘地方使用。

相關文章
相關標籤/搜索