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