個人理解的軟件設計模式

設計模式介紹

  1. 什麼是設計模式

模式的廣義描述:每一個模式描述了一個不斷重複發生的問題,以及該問題的解決方案的核心。這樣,就能一次又一次地使用該方案而不必做重複勞動”。

面向對象設計模式的描述:“被用來在特定場景下解決一般設計問題的類和相互通信的對象的描述”。

既適用於面向對象的開發,也適用於面向過程的開發。

基本要素

  1. 模式名稱(pattern name):一個助記名,它用一兩個詞來描述模式的問題、解決方案和效果。模式名可以幫助我們思考,便於我們與其他人交流設計思想及設計結果。
  2. 問題(problem):描述了應該在何時使用模式。解釋設計問題和問題存在的前因後果,一般會包括使用模式必須滿足的一系列先決條件(語境)。

確定一個模式可能應用到的所有場景,不論是一般的還是特殊的,實際上是不可能的。一個更實際的方法是列出特殊模式關注問題可能出現的所有已知場景。這並不保證包括與一個模式相關的所有場景,但至少它給出了有價值的指導。

  1. 解決方案(solution):描述了設計的組成成分,它們之間的相互關係及各自的職責和協作方式。

因爲模式就像一個模板,可應用於多種不同場合,所以解決方案並不描述一個特定而具體的設計或實現,而是提供設計問題的抽象描述和怎樣用一個具有一般意義的元素組合(類或對象組合)來解決這個問題。

  1. 效果(consequences) 描述了模式應用的效果及使用模式應權衡的問題。

模式效果包括它對系統的靈活性、擴充性或可移植性等方面的影響,顯式地列出這些效果對理解和評價這些模式很有幫助。

兩個概念

組件(component:是軟件系統的一個封裝部分。組件有一個接口。組件可表示爲模塊、類、對象或是一組相關函數。

 

框架( Framework ):是構成一類特定軟件可複用設計的一組相互協作的類。框架規定了應用的體系結構。定義了整體結構,類和對象的分割,各部分的主要責任,類和對象怎麼協作,以及控制流程,框架更強調設計複用。

推薦書籍:

“Design patterns:Elements of Reusable Object-Oriented Software ”,by Gamma,Helm,Johnson&Vlissides,1994。(設計模式:可複用面向對象軟件的基礎)

“Pattern-Oriented Software Software Architecture Volume 1:A System of Patterns”by Buscmann,Meunier,Rohnert,Sommerlad,Stal,1996。(面向模式的軟件體系結構 卷1:模式系統)

  1. 設計模式的主要目標

設計模式的主要目標是支持高質量的軟件系統開發,所謂“高質量”是指系統既能實現其功能需求又實現其非功能需求,尤其強調非功能需求的重要性。

功能屬性(functional property)

用來處理系統功能性的特定方面,並且通常與特定的功能需求相關。功能特性可以通過特定的功能使用戶直接可看到應用程序,也可以通過它的實現來描述,例如用來計算功能的算法。

非功能屬性(non-functional property)

定義了未被功能屬性描述覆蓋的系統特徵。非功能屬性通常解決與一個軟件系統的可靠性、兼容性、開銷、易用性、維護或者開發有關的方面。開發者過去習慣於專心給軟件提供一定的功能屬性,而今天,非功能屬性變得越來越重要。

易修改性:

  • 可維護性。主要體現在問題的修復上:在錯誤發生後“修復”軟件系統。爲可維護性做好準備的軟件體系結構往往能做局部性的修改並能使對其他組件的負面影響最小化。
  • 可擴展性。關注的是使用新特性來擴展軟件系統,以及使用改進版本來替換組件並刪除不需要或不必要的特性和組件。爲了實現可擴展性,軟件系統需要鬆散耦合的組件。其目標是實現一種結構,它能使你在不影響組件客戶的情況下替換組件。支持把新組件集成到現有的體系結構中也是必要的。
  • 結構重組。這一點處理的是重新組織軟件系統的組件及組件間的關係,例如通過將組件移動到一個不同的子系統而改變它的位置。爲了支持結構重組,軟件系統需要精心設計組件之間的關係。理想情況下,它們允許在不影響實現的主體部分的情況下靈活地配置組件。

可移植性。它使軟件系統適用於多種硬件平臺、用戶界面、操作系統、編程語言或編譯器。爲了實現可移植,需要按照硬件無關的方式組織軟件系統,其他軟件系統和環境被提取出來放到特定的組件(如系統和用戶界面庫)中。

注:文檔的重要性。通過採用準確的文檔,在引入更改時保留體系結構,認真評審和爲更改預留空間的方式來防止軟件老化所帶來的開銷。

互操作性:

作爲系統組成部分的軟件不是獨立存在的,它經常與其他系統或自身環境相互作用,爲了支持互操作性,軟件體系結構必須爲外部可視的功能特性和數據結構提供精心設計的軟件入口。程序和用其他編程語言編寫的軟件系統的交互作用就是互操作性的問題,這種互操作性也影響應用的軟件體系結構。代理者模式可能是模式解決互操作性問題的最明顯的例子。

    效率:

效率爲軟件的執行而處理可獲得資源的使用問題,並考慮它是如何影響響應時間、吞吐率和存儲開銷的。效率不僅僅是使用複雜算法的問題。對組件及其耦合來說,恰當地分配責任是在給定的應用程序中爲提高效率而執行的重要的體系結構活動。

可靠性:

可靠性是軟件系統在應用或系統錯誤面前,在意外或錯誤使用的情況下維持軟件系統的功能特性的基本能力。可靠性可以分爲兩個方面:

  • 容錯:其目的是在錯誤發生時確保系統正確的行爲,並進行內部“修復”。例如在一個分佈式軟件系統中失去了一個與遠程組件的連接,接下來恢復了連接。在修復這樣的錯誤之後,軟件系統可以重新或重複執行進程間的操作直到錯誤再次發生。

健壯性:這裏說的是保護應用程序不受錯誤使用和錯誤輸入的影響,在遇到意外錯誤事件時確保應用系統處於已經定義好的狀態。值得注意的是,和容錯相比,健壯性並不是說在錯誤發生時軟件可以繼續運行—它只能保證軟件按照某種已經定義好的方式終止執行。

可測試性:

軟件系統需要從其體系結構上得到支持以減輕對其正確性的評估。支持可測試性的軟件結構可以更好地進行錯誤檢測和修復,也可以臨時性地集成正在調試的代碼和正在調試的組件。

例如,命令處理器模式通過記錄日誌和重現用戶命令對象,促進了用戶交互層次的可測試性。

可重用性:

可重用性是目前軟件工程領域中討論最熱門的話題之一,能夠減少開發軟件系統的費用和時間,並且能夠開發出更高質量的軟件。可重用性有兩個主要方面—使用重用進行軟件開發和爲重用進行軟件開發:

  • 使用重用進行軟件開發:是指重用現有的組件和來自以前項目或商業庫、設計分析、設計說明或代碼組件的結果。這些可重用的人工製品將稍做修改或不做任何修改集成到正在開發的應用程序中去。
  • 爲重用進行軟件開發的重點集中在產生那些既是目前軟件開發的一個組成部分,又有可能在未來項目中重用的組件。這要求軟件體系結構允許自包含部件,這樣不僅正在開發的應用中可用而且在其他系統內重用時不需要做很大的修改。

儘管模式不能明確地解決可重用性的問題,但是幾乎每種支持易修改性的模式也支持可重用性。

 

非功能屬性可能在相互補充的同時又彼此矛盾。當爲軟件體系結構定義非功能需求時,需要仔細考慮它們之間彼此依賴又相互獨立的關係。同時你也需要列出不同非功能需求之間的優先級清單,定義在發生衝突時優先考慮的需求。

非功能屬性是難以度量的。估算軟件體系結構實現一個給定非功能屬性的程度仍然主要依賴於軟件工程師的經驗。

  1. 軟件設計的幾個基本原理(啓用技術)

設計模式是明確建立在用來構造定義良好的軟件系統的啓用技術的基礎上。

抽象:

對象的基本特性,這種特性將對象和所有其他類型的對象區分開,並因此提供清晰定義的相對於觀衆觀點的概念性邊界。 用“組件”替換“對象”可以獲得抽象更普通的定義。包括結構抽象、行爲抽象、關聯關係抽象。

封裝:

封裝將構成抽象結構和行爲的抽象元素分組,並且把不同的抽象彼此分開。封裝提供抽象之間的清晰界限。

信息隱藏:

信息隱藏涉及對客戶隱藏組件的實現細節,以便更好地處理系統複雜性並且使組件之間的耦合減少到最小。信息隱藏是軟件工程領域內基本和最重要的原理之一。

模塊化:

模塊化涉及到對軟件系統有意義的分解,並且將其分成子系統和組件。模塊化的主要目標是通過在程序中引入定義良好的且經過證實的邊界來處理系統複雜性。模塊化與封裝原理密切相關。解決模塊性的模式例子包括層模式、管道和過濾器模式以及整體-部分模式。

事務分離:

在軟件系統內不同的或無關的責任應該彼此分離。幾乎每一個模式都以某種方式應用了這一基本原理。

例:管道和過濾器(Pipes and Filters)、

 

低耦合度:

耦合度是一個組件與其他組件關聯、知道其他組件的信息或者依賴其他組件的強弱程度的度量。強耦合使一個系統錯綜複雜,因爲當一個組件與其他組件緊密相連時它會難以理解、改變或更正。可以通過設計系統組件之間的弱耦合來降低複雜度。

聚合度:

聚合度是對一個類(模塊)中的各個職責之間相關程度和集中程度的度量。一個具有高度相關職責的類,並且這個類所能完成的工作量不是特別巨大,那麼就具有高聚合度。低聚合度將導致難以理解、難以重用、難以維護。

策略和實現的分離:

軟件系統的組件應該處理策略或實現,但並非要求一個組件同時處理這兩方面的需求

• 策略(policy)組件用於處理對語境敏感的決定。

• 實現(implementation)組件用於處理一種說明非常完全的算法的執行,在這個算法中不需要作出對語境敏感的決定。

接口和實現的分離:

任何組件都應該由兩部分組成:

• 一是接口部分,它定義了由組件提供的功能特性並說明怎樣使用它。

• 二是實現部分,它包括由組件爲功能特性提供的實際代碼。

這個原理的主要目標是保護使用組件的客戶免受實現細節的困擾。接口和實現的分離可使用橋接模式來解決。

 

分而治之:

把一項任務或者組件分成可被獨立設計的更小部分。

  1. 設計模式分類

第一是目的準則,即模式是用來完成什麼工作的。模式依據其目的可分爲創建型(Creational)、結構型(Structural) 、或行爲型(Behavioral)三種。創建型模式與對象的創建有關;結構型模式處理類或對象的組合;行爲型模式對類或對象怎樣交互和怎樣分配職責進行描述。

第二是範圍準則,指定模式主要是用於類還是用於對象。類模式處理類和子類之間的關係,這些關係通過繼承建立,是靜態的,在編譯時刻便確定下來了。對象模式處理對象間的關係,這些關係在運行時刻是可以變化的,更具動態性。

 

 

 

 

目的

 

 

 

創建型

結構型

行爲型

範圍

Factory Method(3.3)

Adapter (類) (4 .1 )

Interpreter(5.3 ) Template Method(5.10)

 

對象

Abstract Factory(3.1) Builder(3.2).Prototype(3.4) Singleton(3.5)

A d a p t e r (對象) ( 4 . 1 ) B r i d g e ( 4 . 2 ) C o m p o s i t e ( 4 . 3 ) D e c o r a t o r ( 4 . 4 ) F a c a d e ( 4 . 5 ) F l y w e i g h t ( 4 . 6 ) P r o x y ( 4 . 7 )

Chain of Responsibility(5.1) C o m m a n d ( 5 . 2 ) I t e r a t o r ( 5 . 4 ) M e d i a t o r ( 5 . 5 ) M e m e n t o ( 5 . 6 ) O b s e r v e r ( 5 . 7 ) S t a t e ( 5 . 8 ) S t r a t e g y ( 5 . 9 ) Vi s i t o r ( 5 . 1 0 )

 

第三種分類:體系結構模式、設計模式、慣用法。

體系結構模式: 可作爲具體軟件體系結構的模板。它們規定一個應用的系統範圍的結構特性,以及對其子系統的體系結構施加的影響。所以體系結構模式的選擇是開發一個軟件系統時的基本設計決策。

設計模式(design pattern): 提供一個用於細化軟件系統的子系統或組件,或它們之間關係的圖式。設計模式是中等規模的模式。它們在規模上比體系結構模式小,但又獨立於特定編程語言或編程範例。

慣用法(idiom):是具體針對一種編程語言的低層模式。慣用法描述如何使用給定語言的特徵來實現組件的特殊方面或它們之間的關係。

      體系結構模式可以用在大粒度設計的開始,設計模式可以用在整個設計階段,慣用法可以用在實現階段。

  1. 幾個常用的設計模式

FACTORY METHOD(工廠方法)—對象創建型模式

1. 意圖

定義一個用於創建對象的接口,讓子類決定實例化哪一個類。Factory Method使一個類的實例化延遲到其子類。

2. 結構

Product

定義工廠方法所創建的對象的接口。

ConcreteProduct

實現Product接口。

Creator

聲明工廠方法,該方法返回一個Product類型的對象。Creator也可以定義一個工廠方法的缺省實現,它返回一個缺省的ConcreteProduct對象。

可以調用工廠方法以創建一個Product對象。

ConcreteCreator(MyApplication

重定義工廠方法以返回一個ConcreteProduct實例。

3. 適用性:

• 當一個類不知道它所必須創建的對象的類的時候。

• 當一個類希望由它的子類來指定它所創建的對象的時候。

4. 協作

• Creator依賴於它的子類來定義工廠方法,所以它返回一個適當的ConcreteProduct實例。

5. 效果

工廠方法不再將與特定應用有關的類綁定到你的代碼中。代碼僅處理Product接口;因此它可以與用戶定義的任何ConcreteProduct類一起使用。

工廠方法的一個潛在缺點在於客戶可能僅僅爲了創建一個特定的ConcreteProduct對象,就不得不創建Creator的子類。

  1. 實現
    1 ) 主要有兩種不同的情況
    1. 第一種情況是,Creator類是一個抽象類並且不提供它所聲明的工廠方法的實現。
    2. 第二種情況是,Creator是一個具體的類而且爲工廠方法提供一個缺省的實現。

2 ) 參數化工廠方法該模式的另一種情況使得工廠方法可以創建多種產品。工廠方法採用一個參數標識要被創建的對象種類。

一個參數化的工廠方法具有如下的一般形式,此處MyProduct和YourProduct是Product的子類:

重定義一個參數化的工廠方法使你可以簡單而有選擇性的擴展或改變一個Creator生產的產品。你可以爲新產品引入新的標識符,或可以將已有的標識符與不同的產品相關聯。例如,子類MyCreator可以交換MyProduct和YourProduct並且支持一個新的子類TheirProduct:

注意這個操作所做的最後一件事是調用父類的Create。這是因爲MyCreator::Create僅在對YOURS、MINE和THEIRS的處理上和父類不同。

3 ) 使用模板以避免創建子類,提供Creator的一個模板子類,它使用Prduct類作爲模板參數:

使用這個模板,客戶僅提供產品類—而不需要創建Creator的子類。

 

ABSTRACT FACTORY(抽象工廠)—對象創建型模式

1. 意圖

提供一個創建一系列相關或相互依賴對象的接口,而無需指定它們具體的類。

2. 結構

• AbstractFactory

— 聲明一個創建抽象產品對象的操作接口。

•ConcreteFactory

— 實現創建具體產品對象的操作。

•   AbstractProduct

— 爲一類產品對象聲明一個接口。

•   ConcreteProduct

— 定義一個將被相應的具體工廠創建的產品對象。

— 實現AbstractProduct接口。

•   Client

— 僅使用由AbstractFactory和AbstractProduct類聲明的接口。

3. 適用性:

• 一個系統要獨立於它的產品的創建、組合和表示時。

• 一個系統要由多個產品系列中的一個來配置時。

• 當你要強調一系列相關的產品對象的設計以便進行聯合使用時。

• 當你提供一個產品類庫,而只想顯示它們的接口而不是實現時。

4. 協作

•   通常在運行時刻創建一個ConcreteFactroy類的實例。這一具體的工廠創建具有特定實現的產品對象。爲創建不同的產品對象,客戶應使用不同的具體工廠。

• AbstractFactory將產品對象的創建延遲到它的ConcreteFactory子類。

  1. 效果

Abstract Factory模式有下面的一些優點和缺點:
1) 分離了具體的類:一個工廠封裝創建產品對象的責任和過程,它將客戶與類的實現分離。

2) 使得易於交換產品系列:只需改變具體的工廠即可使用不同的產品配置,這是因爲一個抽象工廠創建了一個完整的產品系列。

3) 有利於產品的一致性:當一個系列中的產品對象被設計成一起工作時,一個應用一次只能使用同一個系列中的對象,這一點很重要。

4) 難以支持新種類的產品:難以擴展抽象工廠以生產新種類的產品。這是因爲Abstract Factory接口確定了可以被創建的產品集合。支持新種類的產品就需要擴展該工廠接口,這將涉及Abstract Factory類及其所有子類的改變。

 

6. 實現
1) 將工廠作爲單件:一個應用中一般每個產品系列只需一個Concrete Factory的實例。因此工廠通常最好實現爲一個Singleton。

2) 創建產品Abstract Factory僅聲明一個創建產品的接口,真正創建產品是由Concrete Product子類實現的。最通常的一個辦法是爲每一個產品定義一個工廠方法。一個具體的工廠將爲每個產品重定義該工廠方法以指定產品。雖然這樣的實現很簡單,但它卻要求每個產品系列都要有一個新的具體工廠子類,即使這些產品系列的差別很小。

3) 定義可擴展的工廠:Abstract Factory通常爲每一種它可以生產的產品定義一個操作。產品的種類被編碼在操作型構中。增加一種新的產品要求改變Abstract Factory的接口以及所有與它相關的類。一個更靈活但不太安全的設計是給創建對象的操作增加一個參數。該參數指定了將被創建的對象的種類。它可以是一個類標識符、一個整數、一個字符串,或其他任何可以標識這種產品的東西。實際上使用這種方法,Abstract Factory只需要一個“Make”操作和一個指示要創建對象的種類的參數。

 

TEMPLATE METHOD(模板方法)—類行爲型模式

1. 意圖

定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。Template Method使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。

2. 結構

• Abstract Class(抽象類)

— 定義抽象的原語操作(primitive operation),具體的子類將重定義它們以實現一個算法

— 實現一個模板方法,定義一個算法的骨架。該模板方法不僅調用原語操作,也調用定義在Abstract Class或其他對象中的操作。

• Concrete Class(具體類)

  • 實現原語操作以完成算法中與特定子類相關的步驟。

 

3. 適用性:

• 一次性實現一個算法的不變的部分,並將可變的行爲留給子類來實現。

• 各子類中公共的行爲應被提取出來並集中到一個公共父類中以避免代碼重複。

4. 協作

• ConcreteClass靠Abstract Class來實現算法中不變的步驟。

  1. 效果

模板方法是一種代碼複用的基本技術。

  1. 實現

一個模板方法調用的原語操作可以被定義爲保護成員。這保證它們只被模板方法調用。必須重定義的原語操作須定義爲純虛函數。模板方法自身不需被重定義;因此可以將模板方法定義爲一個非虛成員函數。

FACADE(外觀)—對象結構型模式

  1. 意圖

爲子系統中的一組接口提供一個一致的界面,Facade模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。

  1. 結構

Facade

— 知道哪些子系統類負責處理請求。

— 將客戶的請求代理給適當的子系統對象。

Subsystem classes

— 實現子系統的功能。

— 處理由Facade對象指派的任務。

— 沒有facade的任何相關信息;即沒有指向facade的指針。

 

  1. 適用性:

• 當你要爲一個複雜子系統提供一個簡單接口時。Facade可以提供一個簡單的缺省視圖,這一視圖對大多數用戶來說已經足夠,而那些需要更多的可定製性的用戶可以越過facade層。

• 客戶程序與抽象類的實現部分之間存在着很大的依賴性。引入facade將這個子系統與客戶以及其他的子系統分離,可以提高子系統的獨立性和可移植性。

• 當你需要構建一個層次結構的子系統時,使用facade模式定義子系統中每層的入口點。如果子系統之間是相互依賴的,你可以讓它們僅通過facade進行通訊,從而簡化了它們之間的依賴關係。

  1. 協作

• 客戶程序通過發送請求給Facade的方式與子系統通訊,Facade將這些消息轉發給適當的子系統對象。儘管是子系統中的有關對象在做實際工作,但Facade模式本身也必須將它的接口轉換成子系統的接口。

• 使用Facade的客戶程序不需要直接訪問子系統對象。
 

  1. 效果

1) 它對客戶屏蔽子系統組件,因而減少了客戶處理的對象的數目並使得子系統使用起來更加方便。

2) 它實現了子系統與客戶之間的松耦合關係,而子系統內部的功能組件往往是緊耦合的。松耦合關係使得子系統的組件變化不會影響到它的客戶。

 

6. 實現
1) 降低客戶-子系統之間的耦合度。用抽象類實現Façade,而它的具體子類對應於不同的子系統實現,這可以進一步降低客戶與子系統的耦合度。另一種方法是用不同的子系統對象配置Facade對象,爲定製facade,僅需對它的子系統對象(一個或多個)進行替換即可。

 

 

BRIDGE(橋接)—對象結構型模式

  1. 意圖

將抽象部分與它的實現部分分離,使它們都可以獨立地變化。

  1. 結構

 

• Abstraction

— 定義抽象類的接口。

— 維護一個指向Implementor類型對象的指針。

• RefinedAbstraction

— 擴充由Abstraction定義的接口。

• Implementor

— 定義實現類的接口,該接口不一定要與Abstraction的接口完全一致;事實上這兩個接口可以完全不同。一般來講,Implementor接口僅提供基本操作,而Abstraction則定義了基於這些基本操作的較高層次的操作。

• ConcreteImplementor

實現Implementor接口並定義它的具體實現。

 

  1. 適用性:

• 不希望在抽象和它的實現部分之間有一個固定的綁定關係。例如這種情況可能是因爲,在程序運行時刻實現部分應可以被選擇或者切換。

• 類的抽象以及它的實現都應該可以通過生成子類的方法加以擴充。這時Bridge模式使你可以對不同的抽象接口和實現部分進行組合,並分別對它們進行擴充。

• 對一個抽象的實現部分的修改應對客戶不產生影響,即客戶的代碼不必重新編譯。

•有許多類要生成。

  1. 協作

• Abstraction將client的請求轉發給它的Implementor對象。

  1. 效果

1) 分離接口及其實現部分。一個實現未必不變地綁定在一個接口上,抽象類的實現可以在運行時刻進行配置,一個對象甚至可以在運行時刻改變它的實現。

 

2) 提高可擴充性。可以獨立地對Abstraction和Implementor層次結構進行擴充。

3 ) 實現細節對客戶透明。

  1. 實現
    1) 僅有一個Implementor 在僅有一個實現的時候,沒有必要創建一個抽象的Implementor類。這是Bridge模式的退化情況.

2) 如果Abstraction知道所有的Concrete Implementor類,它就可以在它的構造器中對其中的一個類進行實例化,它可以通過傳遞給構造器的參數確定實例化哪一個類。

也可以代理給另一個對象,由它一次決定,例如引入一個factory對象(參見Abstract Factory)。

 

SINGLETON(單件)—對象創建型模式

  1. 意圖

保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。

  1. 結構

• Singleton

— 定義一個Instance操作,允許客戶訪問它的唯一實例。Instance是一個類操作C++中的一個靜態成員函數)。

  • 可能負責創建它自己的唯一實例。

 

  1. 適用性:

• 當類只能有一個實例而且客戶可以從一個衆所周知的訪問點訪問它時。

  1. 協作

客戶只能通過Singleton的Instance操作訪問一個Singleton的實例。

  1. 效果
    1. 對唯一實例的受控訪問因爲Singleton類封裝它的唯一實例,所以它可以嚴格的控制客戶怎樣以及何時訪問它。
    2. 是對全局變量的一種改進。它避免了那些存儲唯一實例的全局變量污染名空間。
  2. 實現
    1) 保證一個唯一的實例

 

客戶僅通過Instance成員函數訪問這個單件。變量_instance初始化爲0,而靜態成員函數Instance返回該變量值,如果其值爲0則用唯一實例初始化它。

STRATEGY(策略)—對象行爲型模式

  1. 意圖

定義一系列的算法,把它們一個個封裝起來, 並且使它們可相互替換。本模式使得算法可獨立於使用它的客戶而變化。

  1. 結構

 

• Strategy(策略)

— 定義所有支持的算法的公共接口。Context使用這個接口來調用某ConcreteStrategy定義的算法。

•ConcreteStrategy(具體策略)

— 以Strategy接口實現某具體算法。

• Context(上下文)

— 用一個ConcreteStrategy對象來配置。

— 維護一個對Strategy對象的引用。

— 可定義一個接口來讓Stategy訪問它的數據。

 

  1. 適用性:

• 許多相關的類僅僅是行爲有異。“策略”提供了一種用多個行爲中的一個行爲來配置一個類的方法。

• 需要使用一個算法的不同變體。

• 一個類定義了多種行爲, 並且這些行爲在這個類的操作中以多個條件語句的形式出現。將相關的條件分支移入它們各自的Strategy類中以代替這些條件語句。

 

  1. 協作

• Strategy 和Context相互作用以實現選定的算法。當算法被調用時, Context可以將該算法所需要的所有數據都傳遞給該Stategy。或者,Context可以將自身作爲一個參數傳遞給Strategy操作。這就讓Strategy在需要時可以回調Context。

• Context 將它的客戶的請求轉發給它的Strategy。客戶通常創建並傳遞一個Concrete Strategy 對象給該Context;這樣, 客戶僅與Context交互。通常有一系列的Concrete Strategy類可供客戶從中選擇。

 

  1. 效果

1 ) 相關算法系列。Strategy類層次爲Context定義了一系列的可供重用的算法或行爲。繼承有助於析取出這些算法中的公共功能。

2) 一個替代繼承的方法繼承提供了另一種支持多種算法或行爲的方法。將算法封裝在獨立的Strategy類中使得你可以獨立於其Context改變它,使它易於切換、易於理解、易於擴展。

3) 消除了一些條件語句Strategy模式提供了用條件語句選擇所需的行爲以外的另一種選擇。

5 ) 客戶必須瞭解不同的Strategy 本模式有一個潛在的缺點,就是一個客戶要選擇一個合適的Strategy就必須知道這些Strategy到底有何不同。此時可能不得不向客戶暴露具體的實現問題。

6 ) 增加了對象的數目Strategy增加了一個應用中的對象的數目。

 

  1. 實現
    1) 定義Strategy和Context接口,Strategy和Context接口必須使得Concrete Strategy能夠有效的訪問它所需要的Context中的任何數據. 一種辦法是讓Context將數據放在參數中傳遞給Strategy;另一種辦法是讓Context將自身作爲一個參數傳遞給Strategy, 該Strategy再顯式地向該Context請求數據。
  1. 實例

TravelApp2類圖

 

TravelApp3類圖:

 

TravelApp4類圖

 

 

TravelAfx類圖:

 

  1. 其他
  1. 過分設計

隨着模式使用的增加,我們已經看見有人做得太過分了。類不再簡單。代碼的每“大塊”都非常靈活並且能適合許多不同的環境。這樣的靈活性,無論如何都是要付出很大代價的。靈活的軟件經常會使用間接方式或者不斷增加的存儲消耗來消耗更多的資源。它也在編碼過程中需要更多的思考和更多的工作。好的設計者因此試着提前確定軟件中哪些部分需要非常靈活以處理可預知的變化,哪些部分保持相對穩定。如果經過證明,它們是錯誤的,仍然可以通過仔細地重構系統的某些部分來引入另外的靈活性,或通過使用支持變更設計的模式來完成。這方法相比從一開始就考慮整體易修改性的工程技術更加經濟實惠。

  1. 模式採掘
  2. 方法學
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章