|
抽象與實(shí)現(xiàn)
抽象不應(yīng)該依賴于實(shí)現(xiàn)細(xì)節(jié),實(shí)現(xiàn)細(xì)節(jié)應(yīng)該依賴于抽象。
問(wèn)題在于如果抽象B由于固有的原因,本身并不穩(wěn)定,也有可能變化,怎么辦?
舉例來(lái)說(shuō)
假如我們需要開(kāi)發(fā)一個(gè)同時(shí)支持PC和手機(jī)的坦克游戲,游戲在PC和手機(jī)上功能都一樣,都有同樣的類型,面臨同樣的功能需求變化,比如坦克可能有很多種不同的型號(hào):T50,T75,T90……對(duì)于其中的坦克設(shè)計(jì),我們可能很容易設(shè)計(jì)出來(lái)一個(gè)Tank的抽象基類,然后各種不同型號(hào)的Tank繼承自該類;
另外的變化原因
但是PC和手機(jī)上的圖形繪制、聲效、操作等實(shí)現(xiàn)完全不同……因此對(duì)于各種型號(hào)的坦克,都要提供各種不同平臺(tái)上的坦克實(shí)現(xiàn):
這樣的設(shè)計(jì)會(huì)帶來(lái)很多問(wèn)題:有很多重復(fù)代碼,類的結(jié)構(gòu)過(guò)于復(fù)雜,難以維護(hù),最致命的是引入任何新平臺(tái),比如在TV上的Tank游戲,都會(huì)讓整個(gè)類層級(jí)結(jié)構(gòu)復(fù)雜化。
動(dòng)機(jī)(Motivation)
思考上述問(wèn)題的癥結(jié):事實(shí)上由于Tank類型的固有邏輯,使得Tank類型具有了兩個(gè)變化的維度——一個(gè)變化的維度為“平臺(tái)的變化”,一個(gè)變化的維度為“型號(hào)的變化”。如何應(yīng)對(duì)這種“多維度的變化”?如何利用面向?qū)ο蠹夹g(shù)來(lái)使得Tank類型可以輕松地沿著“平臺(tái)”和“型號(hào)”兩個(gè)方向變化,而不引入額外的復(fù)雜度?
意圖(Intent)
將抽象部分與實(shí)現(xiàn)部分分離,使它們都可以獨(dú)立地變化。
——《設(shè)計(jì)模式》GoF
橋模式不能只是認(rèn)為是抽象和實(shí)現(xiàn)的分離,它其實(shí)并不僅限于此。如下面的例子,兩個(gè)都是抽象的部分。更確切的理解,應(yīng)該是將一個(gè)事物中多個(gè)維度的變化分離。
例說(shuō)Bridge應(yīng)用
版本一
先寫各種不同的坦克型號(hào)類T50、T75等繼承自Tank,然后再讓各種平臺(tái)的坦克繼承自對(duì)應(yīng)型號(hào)的類,如PCT50,PCT75繼承自T50等。這樣設(shè)計(jì)可能會(huì)有很多重復(fù)的代碼,例PCT50和PCT75。
版本二
因?yàn)槠脚_(tái)和坦克型號(hào)都是變化,所以我們把平臺(tái)的變化作為屬性放到基抽象類中。
平臺(tái)實(shí)現(xiàn)類
下面是整個(gè)代碼的骨架
Tank的型號(hào),和Tank的平臺(tái)都繼承自各自的抽象類,因此它們的變化都不會(huì)影響到對(duì)方。而它們之間的關(guān)聯(lián),我們使用組合的方式,把平臺(tái)類放到Tank類中作為屬性。這再次體現(xiàn)了組合優(yōu)先于繼承的思想。多繼承的方法就是版本一的代碼,這種方式子類和父類的關(guān)系太緊,造成緊耦合。
這就是橋模式,把變化引出了基類Tank,使得Tank僅守與型號(hào)的變化。應(yīng)用程序
在環(huán)境交互中使用的都是抽象類,并且把平臺(tái)實(shí)現(xiàn)隱藏,在應(yīng)用程序中new平臺(tái)的方式也可以根據(jù)情況用Singleton模式或者Abstract Factory模式等實(shí)現(xiàn)。
結(jié)構(gòu)(Structure)
其中imp的地方就是一個(gè)組合。Abstraction就是我們之前例子中的Tank,它的子類RefinedAbstraction就是T50等型號(hào)。Implementor是TankPlatformImplementation類,ConcreteImplementorA和ConcreteImplementorB分別是PCTankImplementation和MobileTankImplementation。整個(gè)設(shè)計(jì)模式的關(guān)鍵就是組合的使用。
Bridge模式的幾個(gè)要點(diǎn)
Bridge模式使用“對(duì)象間的組合關(guān)系”解耦了抽象和實(shí)現(xiàn)之間固有的綁定關(guān)系,使得抽象(Tank的型號(hào))和實(shí)現(xiàn)(不同的平臺(tái))可以沿著格子的維度來(lái)變化。所謂抽象和實(shí)現(xiàn)沿著各自維度的變化,即“子類化”它們(比如不同的Tank型號(hào)子類,和不同的平臺(tái)子類),得到各個(gè)子類之后,便可以任意組合它們,從而獲得不同平臺(tái)上的不同型號(hào)。
Bridge模式有時(shí)候類似于多繼承方案,但是多繼承方案往往違背單一職責(zé)原則(即一個(gè)類只有一個(gè)變化的原因),復(fù)用性比較差。Bridge模式是比多繼承方案更好的解決方法。下面是針對(duì)上面的例子,多繼承接口的一種寫法:
這樣PCT50既需要寫T50的實(shí)現(xiàn),又要寫Platform的實(shí)現(xiàn),它把型號(hào)和平臺(tái)的變化都引入了PCT50。這樣就把兩個(gè)本不該扭在一起的事務(wù)扭在了一起,這樣的設(shè)計(jì)更加糟糕,而且也違背了類的單一職責(zé)原則。Bridge模式的應(yīng)用一般在“兩個(gè)非常強(qiáng)的變化維度”,有時(shí)候即使有兩個(gè)變化的維度,但是某個(gè)方向的變化維度并不劇烈——換言之兩個(gè)變化不會(huì)導(dǎo)致縱橫交錯(cuò)的結(jié)果,并不一定要使用Bridge模式。
橋模式并不同于適配器模式,適配器模式其實(shí)是一個(gè)事后諸葛亮,當(dāng)發(fā)現(xiàn)以前的東西不適用了才去做一個(gè)彌補(bǔ)的措施。橋模式相對(duì)來(lái)說(shuō)所做的改變比適配器模式早,它可以適用于有兩個(gè)甚至兩個(gè)以上維度的變化。
it知識(shí)庫(kù):C#面向?qū)ο笤O(shè)計(jì)模式縱橫談:Bridge 橋接模式,轉(zhuǎn)載需保留來(lái)源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。