Adapter適配器:
“一些現存的對象”放在新的環境中應用,但是新環境要求的介面是這些現存對象所不滿足的。
將一個類的介面轉換成客戶希望的另一個介面,Adapter模式使得原本由於介面不相容而不能一起工作的那些類可
以一起工作。
對象適配器:對象組合方式,松耦合
類適配器:採用多繼承實現,用的少
Adapter模式主要應用於“希望複用一些現存的類,但是介面又與複用環境要求不一致的情況”,在遺留代碼複用
,類庫遷移等方面非常有用。
Adapter模式本身要求我們儘可能使用“面向介面的編程”,這樣才能在後期很方便地適配。
Bridge橋:
例子:我們需要開發一個同時支援PC和手機的坦克遊戲,遊戲在PC和手機上功能都一樣,都有同樣的類型,面臨同樣的功能需求變化,比如坦克可能有多種不同的型號:T50,T75.....對於其中的坦克設計,我們可能很容易設
計出一個Tank的抽象基類,然後各種不同型號的Tank繼承自該類。但是PC和手機的映像繪製、聲效、操作等實現完全不同...因此對於各種型號的坦克,都要提供各種不同平台上的坦克實現。這樣的設計會帶來很多問題:有很多
重複的代碼,類的結構過於複雜,難以維護,最致命的是引入任何新平台,比如TV,都會讓整個類層級結構複雜化
。
問題的癥結:事實上由於Tank類型具有兩個變更維度:
“平台的變化”,“型號的變化”。
如何應對“對維度變化”。
Bridge意圖:將抽象部分與實現(也可以是抽象)部分分離,使它們都可以獨立化。---“多個維度變化”的分離
。
採用對象組合方式。(多繼承也可以實現這個功能,但這樣就變得“緊耦合”)
使得“平台”,“型號”維度獨立變化,然後可以任意組合它們,從而獲得不同平台下的不同型號。
Bridge模式的應用一般在“兩個非常強的變化維度”,有時候即使有兩個變更維度,但是某個方向的變化維度並
不劇烈---換言之兩個變化不會導致縱橫交錯的結果,並不一定要使用Bridge模式。
Composite組合:
一類具有“容器”特徵的對象--即它們在充當對象的時候,又是其他對象的容器。
這時客戶必須知道這個“容器”的結構,並進行複雜的遞迴操作。
上述描述的問題的根源在於:客戶代碼過多依賴於對象容器複雜的內部實現結構,對象容器內部實現結構(而非抽
象介面)的變化將引起客戶代碼的頻繁變化,帶來了代碼的維護性、擴充性等弊端。
意圖:將對象組合成樹形結構以表示“部分-整體”的階層。Composite使得使用者對單個對象和組合對象的使
用具有一致性。(複雜結構操作在對象自身內部就實現,只給外部客戶提供一個簡單的介面)
Decorator裝飾:
例子:假如我們需要為遊戲中開發一種坦克,除了各種型號的坦克外,我們還希望在不同場合中為其增加一下一種
或者多種功能,比如紅外線夜視功能,水陸兩棲功能,衛星定位等等。
常規做法:
//抽象坦克
public abstract class Tank{}
//各種型號
public class T50:Tank{}
public class T75:Tank{}
public class T80:Tank{}
//各種不同功能組合
public class T50A:T50,IA{}
public class T50B:T50,IB{}
public class T75AB:T75,IA,IB{}
......
上述問題在於我們“過度使用了繼承來擴充項物件的功能”,由於繼承為類型引入的靜態特質,使得這種擴充方式缺
乏靈活性,並隨著子類的增多(加一個功能,就加一個子類),各種功能的組合會導致更多子類的膨脹。
如何使“對象功能的擴充”能夠根據需要來動態地實現(運行時)?同時避免子類膨脹問題?從而使得任何“功能
擴充變化”所導致的影響降為最低?
Decorator意圖:動態地給一個對象增加一些額外的職責(功能)。
public abstract Tank{}
public abstract T50:Tank{}
public Decorator:Tank{調用Tank的函數功能}
//不是is a的關係,在實現表現為Has a的組合關係
//功能
public DecoratorA:Decorator{建構函式中傳入Tank類型
}
public DecoratorB:Decorator{建構函式中傳入Tank類型
}
public DecoratorC:Decorator{建構函式中傳入Tank類型
}
class App
{Tank tank50= new T50();
DecoratorA da=new DecoratorA(tank50);
DecoratorC da=new DecoratorC(tank50);
Tank tank75= new T75();
DecoratorA da=new DecoratorA(tank75);
DecoratorC da=new DecoratorC(tank75);//這樣就可以
隨意的擴充。
}
Decorator模式並非解決“多子類衍生的多繼承”問題,而在於解決“主體類在多個方向上的擴充功能”---這就
是裝飾的含義。
Facade外觀:
如何簡化外部客戶程式和系統間的互動介面?如何將外部客戶程式的演化和內部子系統的變化之間的依賴相互解耦
。
Facade意圖:為子系統的一組介面提供一個一致的介面,
Facade模式定義了一個高層介面,這個介面使得這一子系統更加容易使用。
要點:
1.不僅簡化了整個組件系統的介面,同時對於組件內部與外部客戶程式來說,從某種成都上也達到了一種“解耦”
的效果---內部子系統的任何變化不會影響到Facade介面的變化。
2.Facade設計模式更注重從架構的層次去看整個系統,而不是單個類的層次,Facade很多時候更是一種架構設計模式。
3.Facade模式注重簡化介面,Adapter模式注重轉換介面,Bridge模式注重分離介面(抽象)與實現,Decorator模
式注重穩定介面的前提下為對象擴充功能。
Flyweight享元(用得少):
採用純粹對象方案的問題在於大量細粒度的對象會很快充斥在系統中,從而帶來很高的運行時代價---主要指向內
存需求方面的代價。
如何在避免大量細粒度對象問題的同時,讓外部客戶程式仍然能夠透明地使用物件導向的方式來進行操作?
Flyweight意圖:運用共用技術有效地支援大量細粒度的對象。
Flyweight模式主要解決物件導向的代價問題,一般不觸及物件導向的抽象性問題。
Flyweight採用共用的做法來降低系統中對象的個數,從而降低細粒度對象給系統帶來的記憶體壓力。
Proxy代理:
有些對象由於某種原因(比如對象建立的開銷大,或者某些操作需要安全控制,或者需要進程外的訪問等),直接
訪問會給使用者、或者系統結構帶來很多麻煩。
如何在不失去透明操作對象的同時來管理、控制這些對象特有的複雜性?增加一層間接層是軟體開發中常見的解決
方式。
Proxy意圖:為其他對象提供一種代理以控制對這個對象的訪問。
結構型設模式總結:
Adapter模式注重轉換介面,將不吻合的介面匹配對象。
Bridge模式注重分離介面與其實現,支援多維度變化。(介面可能也不穩定)
Composite模式注重統一介面,將“一對多”的關係轉化為“一對一”的關係。(容器,結構複雜)
Decorator模式注重穩定介面,在此前提下為對象擴充功能。
Facade模式注重簡化剪口,簡化組件系統與外部客戶程式的依賴關係。
FlyWeight模式注重保留介面,在內部使用共用技術對Object Storage Service進行最佳化。
Proxy模式注重假借介面,增加間接層來實現靈活控制。