每個模式都描述了某個特定場景中一個特定問題的限制因素/動機和關系,并為設計者提供一種解決這些問題的優雅方案。換句話說,模式僅僅是描述了特定場景下的關系和限制因素,正因如此,模式本身并不是最重要的,特定場景下的關系和限制因素才是最真實的,而模式僅僅是提供了一組描述這些關系的一組詞彙,提供了一套解決這些關系的優雅方式而已。
在軟體設計中,模式是随特定場景下的關系和限制因素而定的。也就是說,對所要解決問題的分析和了解是使用模式的必要條件。隻有清楚了特定場景下的關系和限制因素,才能很好地選擇解決問題的方法和适用的模式。
特定模式描述的是問題中概念(抽象類)之間的關系,比如所有的行為模式,bridge模式等;或者是抽象類和派生類之間的關系,比如Proxy,Composite,Decorator等;抑或是新類和原有類之間的關系,如Adaptor,Facade等。這些關系未必是顯而易見的,它們都是問題分析的結果。沒有從概念視角對問題的分析,這些關系是不能凸現出來的。是以,使用模式應該建立在共性與可變分析、分析矩陣等方法的基礎上。在概念視角層次上的分析,往往考慮的是抽象類之間的關系,是以這時所采用的模式一般是行為模式、bridge模式等。描述抽象類和派生類之間關系的模式一般應該等到實作層次時才考慮引入。這種分層設計有助于簡化設計過程,忽略不必要的次要因素,産生更好的高層設計。
根據上述觀點,雖然模式經常是組合使用,但模式的使用順序是有先後之分的。在高層設計會采用一些高層的主模式,在代碼實作級别上,也會再次引入其他合适的模式。個人覺得行為模式、Bridge、Facade等模式是最常用的主模式。
(注:這裡僅針對靜态語言,在動态語言中,多态并非通過繼承實作)
封裝/繼承/多态都是面向對象的基本概念。前面已經講過,封裝變化是模式的核心思想之一。同時,從抽象類和派生類的角度看,繼承和多态使得抽象類能夠封裝派生類的類型。顯然,繼承和多态使類封裝變化成為可能。是以,在設計模式中,繼承是随處可見的。
從模式角度看,模式是面向對象複用的基礎元素。采用模式可使設計的軟體更加靈活,更易擴充,更易維護,這也正是OCP(開放封閉原則)所強調的。要實作這個目标,繼承也是必不可少的。繼承使派生類之間可互相替換,是以也就封裝了抽象類背後的變化。
一般來說,使用模式是有代價的。模式雖有其自身的優越性,但隻有在問題本身有一定的複雜性時,采用模式來簡化這些複雜性才是有意義的。然而,不能忽略的是:模式本身(所涉及的互相互動的類)是有一定複雜性的。每個模式中互相互動的類之間,可以說是緊密耦合在一起的。這些類基本上是不可分的,它們本身就是作為一個整體而存在。同時這些類背後的繼承關系在使模式靈活的同時,也增加了複雜性。這都是使用模式時需要考慮的因素。切記:模式中的類是作為一個整體而存在,它們是緊密耦合的關系;模式描述了這些類之間的關系和限制因素,豐富設計詞彙,使我們容易交流,但同時要清楚實作時是對這些類和這些互動關系的再現。
設計模式可以確定系統能以特定方式變化(這很大程度是一種預測),進而幫助設計者避免重新設計系統。每一個設計模式允許系統結構的某個部分的變化獨立于其他部分,這樣産生的系統對于某一種特殊變化将更健壯。
下面闡述一些導緻重新設計的一般原因,以及解決這些問題的常用設計模式:
1) 通過顯式地指定一個類來建立對象。在建立對象時指定類名将使設計者受特定實作的限制, 而不是特定接口的限制。這會使未來的變化更複雜。要避免這種情況,應該間接地建立對象。
設計模式:Abstract Factory,Factory Method,Prototype。
2) 對特殊操作的依賴。 當設計者為請求指定一個特殊操作時,完成該請求的方式就固定了。避免把請求代碼寫死,可在編譯時刻或運作時刻友善地改變響應請求的方法。
設計模式:Chain of Responsibility,Command。
3) 對硬體和軟體平台的依賴。 外部的作業系統接口和應用程式設計接口(API)在不同的軟硬體平台上是不同的。依賴于特定平台的軟體将很難移植到其他平台上,甚至都很難跟上本地平台的更新。是以設計系統時限制其平台相關性就很重要了。
設計模式:Abstract Factory,Bridge。
4) 對對象表示或實作的依賴。 知道對象怎樣表示、儲存、定位或實作的客戶在對象發生變化時可能也需要變化。對客戶隐藏這些資訊能阻止連鎖變化。
設計模式:Abstract Factory,Bridge,Memento,Proxy
5) 算法依賴。 算法在開發和複用時常常被擴充、優化和替代。依賴于某個特定算法的對象在算法發生變化時不得不變化。是以有可能發生變化的算法應該被孤立起來。
設計模式:Builder,Iterator,Strategy,Template Method,Visitor
6) 緊耦合的類很難獨立地被複用,因為它們是互相依賴的。緊耦合産生單塊的系統,要改變或删掉一個類,必須了解和改變其他類。這樣的系統是一個很難學習、移植和維護的密集體。
松散耦合提高了一個類本身被複用的可能性,并且系統更易于學習、移植、修改和擴充。設計模式使用抽象耦合和分層技術來提高系統的松散耦合性。
設計模式:Abstract Factory,Command,Facade,Mediator,Observer,Chain of Responsibility
7) 通過生成子類來擴充功能。 通常很難通過定義子類來定制對象。每一個新類都有固定的實作開銷(初始化、終止處理等)。定義子類還需要對父類有深入的了解。如,重定義一個操作可能需要重定義其他操作。一個被重定義的操作可能需要調用繼承下來的操作。并且子類方法會導緻類爆炸,因為即使對于一個簡單的擴充,也不得不引入許多新的子類。(本質: 繼承應該僅僅封裝一個變化點)
一般的對象組合技術和具體的委托技術,是繼承之外組合對象行為的另一種靈活方法。新的功能可以通過以新的方式組合已有對象,而不是通過定義已存在類的子類的方式加到應用中去。另一方面,過多使用對象組合會使設計難于了解。許多設計模式産生的設計中,設計者可定義一個子類,且将它的執行個體和已存在執行個體進行組合來引入定制的功能。
設計模式:Bridge,Chain of Responsibility,Composite,Decorator,Observer,Strategy
8) 不能友善地對類進行修改。 有時設計者不得不改變一個難以修改的類。也許你需要源代碼而又沒有(對于商業類庫就有這種情況),或者可能對類的任何改變會要求修改許多已存在的其他子類。設計模式提供在這些情況下對類進行修改的方法。
設計模式:Adapter,Decorator,Visitor
設計模式與其封裝的變化點
設計模式
變化點
建立型
Abstract Factory
産品對象家族
Builder
組合建立組合(複雜) 對象
Factory Method
被執行個體化的子類(相關類)
Prototype
被執行個體化的類
Singleton
一個類的唯一執行個體
Object Factory
被執行個體化的類,Factory Method的變種
Object Pool
對象管理和重用,Factory Method的變種
Creation Method
類的構造函數,Factory Method的變種
結構型
Adapter
對象的接口(可變API)
Bridge
對象實作(實作邏輯)
Composite
對象的結構群組成
Decorator
對象的職責(職責組合)
Façade
子系統的接口(子系統的變化)
Flyweight
對象的存儲
Proxy
對象的通路和對象的位置
行為型
Chain of Responsibility
滿足某個請求的對象(請求的實際處理對象)
Command
何時、如何實作某個請求
Interpreter
一個語言的文法和解釋
Iterator
如何周遊、通路一個聚合的各元素
Mediator
對象間的互動邏輯
Memento
對象資訊的存儲管理
Observer
對象間的依賴和通訊
State
對象狀态
Strategy
算法
Template Method
算法某些步驟
Visitor
作用于對象上的操作
---------------------------------------------------
歡迎轉載,請注明作者和出處
本文轉自 zhenjing 部落格園部落格,原文連結: http://www.cnblogs.com/zhenjing/archive/2010/12/07/disign_pattern.html ,如需轉載請自行聯系原作者