第一篇:設計模式之創建型模式
在這部分里,我們關注GoF里面的結構型模式,它主要是用於描述如何將類組合在一起去構成更大的結構。結構型模式包括適配器(Adapter)、裝飾(Decorator)、橋接器(Bridge)、享元(FlyWeight)、門面(Facade)、合成(Composite)以及代理(Proxy)模式。
下面我們對上面提到的模式分別進行描述。
1)適配器(Adapter)。當我們已經開發出一個模塊,有一套清晰的接口,並且模塊正在被某個功能使用(意味着模塊接口改變的可能性不高),這是如果有另外一個功能也需要使用這個模塊的功能,但是對應的是一套完全不同的接口,這時適配器就可以發揮作用了。
適配器模式分為兩種,一種是對象適配器,一種是類適配器,對象適配器的UML圖如下:
這里Adaptee1和Adaptee2指兩套不同的子系統,它們作為Adapter的屬性存在,可以使用IoC的方式指定。
類適配器的UML圖如下:
同樣是兩個不同的子系統,但是這里我們創建了2個Adapter類來分別指向兩個子系統。在這里我們可以在Client和ITarget之間,設置一個Adapter工廠,來根據業務需求創建不同的Adpater實例。
2)裝飾(Decorator),假如我們已經開發了一套功能,然后根據需求,需要增加一些子功能,而且這些子功能是比較分散比較時可以增刪的,這時如果直接修改接口,那么會造成接口功能復雜並且不穩定,針對這種情況,我們可以使用裝飾模式。對應的UML圖如下:
上圖中,ConcreteComponent已經實現了Component的基本功能,對於一些附加的功能,如果放在ConcreteComponent中不合適的話,我們可以像ConcreteDecoratorA一樣,創建一個基於Decorator的類,通過SetComponent方法將核心功能和輔助功能串在一起。
有時,為了簡單,我們也可以把ConcreteDecorator直接掛在Concretecomponent下面。
3)橋接器(Bridge),面向對象提倡的幾個最佳實踐包括:1)封裝變化;2)面向接口編程;3)組合優於繼承;4)類的職責盡量單一。橋接器完美的體現了這些,通過創建型模式,我們可以很好地達到面向接口編程的目標,也就是說我們在程序中各變量的聲明類型是接口類型或者抽象類,而具體的實現類型則由不同的設計模式使用不同方式指定。這在接口或者抽象類基本穩定的情況下,是很好地,但當接口需要發生變化時,我們如何去處理?可以看看橋接器的UML圖:
通過這個圖,我們可以看出,Implementor接口的變化,對於Client來說,基本是沒有影響的。Abstraction會持有Implementor的一個實例。
4)享元(FlyWeight),當我們系統中需要使用大量的小對象,但我們又不希望將所有的小對象都創建出來時,可以考慮使用享元模式,它會抽取小對象中的公共部分,將其封裝為基類,然后針對不同條件創建小對象,同時在對象池中維護這些小對象,客戶在需要使用小對象時,首先在對象池中查找,如果存在,直接返回。對於小對象中“個性”的部分,由調用小對象的客戶端進行維護。對應的UML圖如下:
除了上述的簡單享元,還存在一種復合享元,對應的UML圖如下:
圖中,CompositeConcreteComponent是不共享的,但是它里面包含很多簡單的享元,這些享元是共享的,我們可以把它想象成一個特殊的“享元工廠”。
通常提到享元,最常見的例子就是文本編輯器中的26個字母,在.NET中,字符串常量也使用了享元模式。
在享元模式中,我們通常會將FlyWeightFactory設計為單例模式,否則享元就沒有意義了。
5)門面(Facade),如果我們的程序需要深入調用某個模塊的內部,但我們又不想和模塊過緊耦合,這時可以考慮使用門面模式,來對外部封裝內部子系統的實現。簡單的門面可能和代理在某種程度上很相似。
門面模式沒有固定的UML圖,它是根據客戶端的實際需求以及子系統內部的接口來確定的。
6)合成(Composite),當我們的對象結構中存在“父子”關系時,可以考慮使用合成模式。它分為兩種,一種是安全型的合成模式,UML圖如下:
這種類型的合成模式,對於Component的增、刪、改,都在Composite中維護,Leaf根本不知道這些操作。另一種是透明型的合成模式,UML圖如下:
這種類型的合成模式,自上而下所有的Component都會有增、刪、改的操作,只不過對於Leaf來說,這些操作時沒有意義的。
7)代理(Proxy),在編寫程序時,有時我們希望使用某個對象或者模塊的功能,但是因為種種原因,我們不能直接訪問,這時就可以考慮使用代理,對應的UML圖如下:
需要注意的是,在這里RealSubject只有一個,如果有多個,那么就是Adapter了。另外,代理也可以加入自己的一些邏輯處理,例如PreExecute和PostExecute。如果這里有多個Proxy,那么就是Decorator了。
上面就是對結構型設計模式的快速瀏覽,其中有很多UML圖看上去很相似,但深入去思考,每個模式的出發點、所要解決的問題是不一樣的。