1. 程式人生 > >C++設計模式總結

C++設計模式總結

設計模式簡介

設計模式為開發人員提供一種使用專家設計經驗的有效途徑。設計模式中運用了面向物件程式語言的重要特徵:封裝、繼承、多型等。

常見的設計模式主要有:工廠模式、策略模式、介面卡模式、單例模式、原型模式、模板方法模式、建造者模式、外觀模式、組合模式、代理模式、享元模式、橋接模式、修飾模式、備忘錄模式、中介者模式、職責鏈模式、觀察者模式、狀態模式。

工廠模式

工廠模式屬於建立型模式,分為以下三類:簡單工廠模式、工廠方法模式、抽象工廠模式。

簡單工廠模式:主要特點是需要在共產類中做判斷,從而建立相應的產品。當增加新產品時,需要修改工廠類。

缺點:需要增加新的型別時,需要修改工廠類。違反了開放封閉原則:軟體實體(類、模組、函式)可以擴充套件,但是不可修改。

工廠方法模式:指定義一個用於建立物件的介面,讓子類決定例項化哪一個類。

缺點:當增加一種新產品,就需要建立一個物件的工廠。當新產品很多時,就會有很多的類定義。

抽象工廠模式:提供一個建立一系列相關或相互依賴物件的介面,而無需指定它們具體的類。

策略模式

策略模式:指定義一系列演算法,把它們一個個封裝起來,並且使它們可相互替換。本模式使得演算法可獨立與使用它的客戶而變化。即演算法所完成的功能和對外介面一樣,只是各自實現細節上存在差異。策略模式封裝演算法,效果比較好。

舉例:Cache替換演算法。當發生Cache缺失時,Cache控制器必須選擇Cache中的一行,並用欲獲得的資料來替換。採用的策略就是Cache替換演算法。

ReplaceAlgorithm是一個抽象類,定義了演算法的介面,有三個雷繼承自這個抽象類,即具體演算法實現。故維護一個ReplaceAlgorithm物件。

Cache定義及實現,直接影響客戶的使用方式。關鍵在於如何指定替換演算法。

1)直接通過引數指定,傳入一個特徵演算法的指標。缺點:客戶需要知道演算法具體定義,從而暴露太多演算法細節。

2)直接通過引數指定,不傳入指標,而是標籤。通過標籤,呼叫對應演算法。與一相比,用起來方便。其實質是簡單工廠模式與策略模式結合。

3)利用模板實現。通過模板指定實參。還實用引數,不過不是建構函式引數。策略模式中,引數傳遞難以避免,客戶必須指定某種演算法。

介面卡模式

介面卡模式:將一個類的介面轉換成客戶希望的另外一個介面,使得原本由於介面不相容而不能一起工作的那些類可以一起工作。它包括類介面卡和物件介面卡。

舉例:STL就用到了介面卡模式。STL實現一種資料結構,雙端佇列,支援前後兩段的插入與刪除。STL實現棧和佇列時,沒有從頭開始定義它們,而是直接使用雙端佇列實現。雙端佇列扮演了介面卡角色。佇列用到了它的後端插入,前端刪除。棧則用到它的後端刪除,後端插入。棧和佇列都是一種順序容器,存在兩種操作:壓入和彈出。

單例模式

單例模式:實現較簡單。其建構函式是私有的,故無法通過建構函式例項化,唯一的方法是通過呼叫靜態函式GetInstance。

原型模式

原型模式:用原型例項指定建立物件的種類,並且通過拷貝這些原型建立新的物件。拷貝是原型模式的精髓。

原型模式實現的關鍵是實現clone函式,對C++而言,其實質是拷貝建構函式,即實現深拷貝。

模板方法模式

模板方法模式:定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。即在父類中定義操作演算法骨架,具體由子類實現。

其中在FillResume()中定義操作的骨架,然後呼叫子類實現函式。

建造者模式

建造者模式:將一個複雜物件的構建與它的表示分離,使得同樣的構造過程可以建立不同的表示。

對使用者來說,只需知道導向者即可,通過導向者,客戶能夠構造複雜的物件,而不需要知道具體的構造過程。

外觀者模式

外觀著模式:使用很多的一種模式,特別是當一個系統很複雜時,系統提供給客戶的是一個簡單的對外介面,而把裡面複雜的結構都封裝起來。客戶只需使用這些簡單介面就能使用這個系統,而不需關注內部複雜的結構。另一種定義:為子系統中的一組介面提供一個一致的節點,外觀模式定義了一個高層介面,這個介面使得這一子系統更加容易使用。

舉例:編譯系統就使用外觀著。原因是編譯系統複雜,實際四個步驟為詞法分析、語法分析、中間程式碼生成、機器碼生成,這四個步驟實現都很複雜,故可定義一個高層介面,如Compiler類,然後定義一個run函式,run函式內部具體實現,對使用者透明,即客戶不需知道。

外觀著模式特點:1)它對客戶遮蔽子系統元件,因而減少了客戶處理的物件的數目並使得子系統使用起來更加方便;2)實現了子系統與客戶之間鬆耦合關係,而子系統內部的功能元件往往是緊耦合的;3)如果應用需要,它並不限制它們使用子系統類。

組合模式

組合模式:將物件組合成樹形結構以表示“整體——部分”的層次結構。組合使得使用者對單個物件和組合物件的使用具有一致性。其關鍵是樹形結構。

代理模式

代理模式:為其他物件提供一種代理以控制對這個物件的訪問。四種常用的情況:1)遠端代理;2)虛代理;3)保護代理;4)智慧引用。

舉例:考慮一個可以在文件中嵌入圖形物件的文件編輯器。有些圖形物件的建立開銷很大。但是開啟文件必須很迅速,故在開啟文件時應避免一次性建立所有開銷很大的物件。在此,運用代理模式,在開啟文件時,並不開啟影象物件,而是開啟圖形物件的代理以替代真實的圖形。待到真正需要開啟圖形時,扔由代理負責開啟。

享元模式

享元模式:運用共享技術有效地支援大量細粒度的物件。

舉例:在圍棋中,棋子就是大量細粒度的物件。其屬性有內在的,如顏色、形狀等,也有外在的,如棋盤位置等。內在的屬性可以共享,區分在外在屬性。故設計時,只需要定義兩個棋子的物件,一顆黑棋和一顆白棋,這兩個物件含棋子的內在屬性,棋子外在屬性,即在棋盤上的位置可以讀取出來,存放在單獨的容器中。容器中只需存放位置,可以減少對空間的需求。

橋接模式

橋接模式:將抽象部分和它的實現部分分離,使它們都可以獨立地變化。

舉例:考慮裝作業系統,有多種配置的計算機,同樣也有多款作業系統。如何運用橋接模式呢?可以將作業系統和計算機分別抽象出來,讓它們各自發展,減少它們的耦合度。當然了,兩者之間有標準的介面。這樣的設計,不論是對於計算機,還是作業系統都是非常有利的。

裝飾模式

裝飾模式:動態地給一個物件新增一些額外的職責。就增加功能來說,裝飾模式相比生成子類更為靈活。有時我們希望給某個物件而不是整個類新增一些功能。

舉例:對有一個手機,允許為其新增特性,如增加掛件、螢幕貼膜等。一個靈活的設計方式是,將手機嵌入到另一個物件中,由這個物件完成特性的新增,稱此嵌入物件為修飾。這個裝飾與其它所裝飾的元件介面一致。故它對使用該元件的使用者透明。

裝飾模式提供了更加靈活的面向物件新增職責的方式。可以用新增和分離的方法,用裝飾在執行時刻增加和刪除職責。裝飾模式提供了一種“即用即付”的方法來新增職責。它並不檢視在一個複雜的可定製的類中支援所有可預見的特徵,相反,你可以定義一個簡單的類,並且用裝飾類給它逐漸地新增功能。可以從簡單的部件組合出複雜的功能。

備忘錄模式

備忘錄模式:在不破壞封裝性的前提下,捕獲一個物件的內部狀態,並在該物件之外儲存這個狀態。這樣以後就可將該物件恢復到原先儲存的狀態。

舉例:玩遊戲時,都會儲存進度,所儲存的進度以檔案的形式存在。下次就可以繼續玩,而不是從頭開始。此處的進度其實就是遊戲的內部狀態,檔案則是遊戲之外的儲存狀態。下次可從檔案中讀取儲存的進度,從而恢復到原來的狀態。這就是備忘錄模式。

Memento類定義了內部的狀態,而Caretake類是一個儲存進度的管理者,GameRole類是遊戲角色類。由上圖可得GameRole的物件依賴於Memento物件,而與Caretake物件無關。

中介者模式

中介者模式:用一箇中介物件來封裝一系列的物件互動。中介者使各物件不需要顯示地相互引用,從而使其耦合鬆散,而且可以獨立地改變它們之間的互動。在軟體中,就是多個物件之間需要通訊,如果沒有中介,物件就需要知道其他物件,最壞情況下,可能需要知道所有其他的物件,而有了中介物件就方便多了,物件只需要與中介物件通訊,而不用知道其他的物件。

職責鏈模式

職責鏈模式:使多個物件都有機會處理請求,從而避免請求的傳送者和接收者之間的耦合關係。這些物件連成一條鏈,並沿著這條鏈傳遞該請求,直到有一個物件處理它為止。

觀察者模式

觀察者模式:定義物件間的一種一對多的依賴關係,當一個物件的狀態發生改變時,所有依賴於它的物件都得到通知並被自動更新。它還有兩個別名,依賴(Dependents),釋出-訂閱(Publish-Subsrcibe)。

舉例:部落格訂閱例子。當博主發表新文章的時候,即博主狀態發生了改變,那些訂閱的讀者就會收到通知,然後進行相應的動作,如去看文章,或者收藏等。博主與讀者之間存在一種一對多的依賴關係。

其中,部落格類中有一個觀察者連結串列(即訂閱者),當部落格的狀態發生變化時,通過Notify成員函式通知所有的觀察者,告訴他們部落格的狀態更新了。而觀察者通過Update成員函式獲取部落格的狀態資訊。部落格類主要完成觀察者的新增、移除、通知等操作,設定和獲得狀態僅僅是一個預設實現。

狀態模式

狀態模式:允許一個物件在其內部狀態改變時改變它的行為。物件看起來似乎修改了它的類。它的兩種使用情況:1)一個物件的行為取決於它的狀態,並且它必須在執行時刻根據狀態改變它的行為;2)一個操作中含有龐大的多分支的條件語句,且這些分支依賴於該物件的狀態。

舉例:以戰爭為例,假設一場戰爭需經歷四個階段:前期、中期、後期、結束。當戰爭處於不同的階段,戰爭的行為是不一樣的,即戰爭的行為取決於所處的階段,而且隨時間的推進是動態變化的。

  • 各種設計模式綜合

    裝飾者模式:包裝一個物件,以提供新的行為。

    狀態模式:封裝了基本狀態行為,並使用委託在行為之間切換。

    迭代器模式:在物件的集合之中游走,而不暴露集合的實現。

    外觀模式:簡化一群類的介面。

    策略模式:封裝可以互換的行為,並使用委託在行為之間切換。

    代理模式:包裝物件,以控制對此物件的訪問。

    工廠方法模式:有子類決定要建立的具體類是哪一個。

    介面卡模式:封裝物件,並提供不同的介面。

    觀察者模式:讓物件能夠在狀態改變時被通知。

    模板方法模式:由子類決定如何實現一個演算法中的步驟。

    組合模式:客戶用一致的方式處理物件集合和單個物件。

    單件模式:確保有且只有一個物件被建立。

    抽象工廠模式:允許客戶建立物件的家族,而無需指定它們的具體類。

    命令模式:封裝請求成為物件。

參考文獻: