<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Vincent

    Vicent's blog
    隨筆 - 74, 文章 - 0, 評論 - 5, 引用 - 0
    數(shù)據(jù)加載中……

    一、 橋梁(Bridge)模式

    一、?橋梁(Bridge)模式

    橋梁模式是一個(gè)非常有用的模式,也是比較復(fù)雜的一個(gè)模式。熟悉這個(gè)模式對于理解面向?qū)ο蟮脑O(shè)計(jì)原則,包括"開-閉"原則(OCP)以及組合/聚合復(fù)用原則(CARP)都很有幫助。理解好這兩個(gè)原則,有助于形成正確的設(shè)計(jì)思想和培養(yǎng)良好的設(shè)計(jì)風(fēng)格。

    注:《Java與模式》一書認(rèn)為Bridge模式不是一個(gè)使用頻率很高的模式,我不太贊同,我認(rèn)為Bridge模式中蘊(yùn)涵了很多設(shè)計(jì)模式的關(guān)鍵思想在里面,所以我這里采納了《Design Patterns Explained》一書的作者Alan Shalloway與James R. Trott的觀點(diǎn):The Bridge pattern is quite a bit more complex than the other patterns you just learned; it is also much more useful.

    橋梁模式的用意

    【GOF95】在提出橋梁模式的時(shí)候指出,橋梁模式的用意是"將抽象化(Abstraction)與實(shí)現(xiàn)化(Implementation)脫耦,使得二者可以獨(dú)立地變化"。這句話有三個(gè)關(guān)鍵詞,也就是抽象化、實(shí)現(xiàn)化和脫耦。

    抽象化

    存在于多個(gè)實(shí)體中的共同的概念性聯(lián)系,就是抽象化。作為一個(gè)過程,抽象化就是忽略一些信息,從而把不同的實(shí)體當(dāng)做同樣的實(shí)體對待【LISKOV94】。

    實(shí)現(xiàn)化

    抽象化給出的具體實(shí)現(xiàn),就是實(shí)現(xiàn)化。

    脫耦

    所謂耦合,就是兩個(gè)實(shí)體的行為的某種強(qiáng)關(guān)聯(lián)。而將它們的強(qiáng)關(guān)聯(lián)去掉,就是耦合的解脫,或稱脫耦。在這里,脫耦是指將抽象化和實(shí)現(xiàn)化之間的耦合解脫開,或者說是將它們之間的強(qiáng)關(guān)聯(lián)改換成弱關(guān)聯(lián)。

    將兩個(gè)角色之間的繼承關(guān)系改為聚合關(guān)系,就是將它們之間的強(qiáng)關(guān)聯(lián)改換成為弱關(guān)聯(lián)。因此,橋梁模式中的所謂脫耦,就是指在一個(gè)軟件系統(tǒng)的抽象化和實(shí)現(xiàn)化之間使用組合/聚合關(guān)系而不是繼承關(guān)系,從而使兩者可以相對獨(dú)立地變化。這就是橋梁模式的用意。


    二、?橋梁模式的結(jié)構(gòu)

    橋梁模式【GOF95】是對象的結(jié)構(gòu)模式,又稱為柄體(Handle and Body)模式或接口(Interface)模式。

    下圖所示就是一個(gè)實(shí)現(xiàn)了橋梁模式的示意性系統(tǒng)的結(jié)構(gòu)圖。

    可以看出,這個(gè)系統(tǒng)含有兩個(gè)等級結(jié)構(gòu),也就是:

    • 由抽象化角色和修正抽象化角色組成的抽象化等級結(jié)構(gòu)。
    • 由實(shí)現(xiàn)化角色和兩個(gè)具體實(shí)現(xiàn)化角色所組成的實(shí)現(xiàn)化等級結(jié)構(gòu)。

    橋梁模式所涉及的角色有:

    • 抽象化(Abstraction)角色:抽象化給出的定義,并保存一個(gè)對實(shí)現(xiàn)化對象的引用。
    • 修正抽象化(Refined Abstraction)角色:擴(kuò)展抽象化角色,改變和修正父類對抽象化的定義。
    • 實(shí)現(xiàn)化(Implementor)角色:這個(gè)角色給出實(shí)現(xiàn)化角色的接口,但不給出具體的實(shí)現(xiàn)。必須指出的是,這個(gè)接口不一定和抽象化角色的接口定義相同,實(shí)際上,這兩個(gè)接口可以非常不一樣。實(shí)現(xiàn)化角色應(yīng)當(dāng)只給出底層操作,而抽象化角色應(yīng)當(dāng)只給出基于底層操作的更高一層的操作。
    • 具體實(shí)現(xiàn)化(Concrete Implementor)角色:這個(gè)角色給出實(shí)現(xiàn)化角色接口的具體實(shí)現(xiàn)。


    三、?橋梁模式的示意性源代碼

    // ?Bridge?pattern?--?Structural?example??
    using ?System;

    // ?"Abstraction"
    class ?Abstraction
    {
    ??
    // ?Fields
    ?? protected ?Implementor?implementor;

    ??
    // ?Properties
    ?? public ?Implementor?Implementor
    ??
    {
    ????
    set {?implementor? = ?value;?}
    ??}


    ??
    // ?Methods
    ?? virtual ? public ? void ?Operation()
    ??
    {
    ????implementor.Operation();
    ??}

    }


    // ?"Implementor"
    abstract ? class ?Implementor
    {
    ??
    // ?Methods
    ?? abstract ? public ? void ?Operation();
    }


    // ?"RefinedAbstraction"
    class ?RefinedAbstraction?:?Abstraction
    {
    ??
    // ?Methods
    ?? override ? public ? void ?Operation()
    ??
    {
    ????implementor.Operation();
    ??}

    }


    // ?"ConcreteImplementorA"
    class ?ConcreteImplementorA?:?Implementor
    {
    ??
    // ?Methods
    ?? override ? public ? void ?Operation()
    ??
    {
    ????Console.WriteLine(
    " ConcreteImplementorA?Operation " );
    ??}

    }


    // ?"ConcreteImplementorB"
    class ?ConcreteImplementorB?:?Implementor
    {
    ??
    // ?Methods
    ?? override ? public ? void ?Operation()
    ??
    {
    ????Console.WriteLine(
    " ConcreteImplementorB?Operation " );
    ??}

    }


    /// ? <summary>
    /// ?Client?test
    /// ? </summary>

    public ? class ?Client
    {
    ??
    public ? static ? void ?Main(? string []?args?)
    ??
    {
    ????Abstraction?abstraction?
    = ? new ?RefinedAbstraction();

    ????
    // ?Set?implementation?and?call
    ????abstraction.Implementor? = ? new ?ConcreteImplementorA();
    ????abstraction.Operation();

    ????
    // ?Change?implemention?and?call
    ????abstraction.Implementor? = ? new ?ConcreteImplementorB();
    ????abstraction.Operation();
    ??}

    }


    四、?調(diào)制解調(diào)器問題

    感覺《敏捷軟件開發(fā)-原則、模式與實(shí)踐》中關(guān)于Bridge模式的例子很好。(《Java與模式》一書33章的對變化的封裝一節(jié)也寫得很不錯(cuò),推薦大家讀一讀。它深入的闡述了《Design Patterns Explained》一書中"1)Design to interfaces. 2)Favor composition over inheritance. 3)Find what varies and encapsulate it"的三個(gè)觀點(diǎn)。)。

    如圖所示,有大量的調(diào)制解調(diào)器客戶程序在使用Modem接口。Modem接口被幾個(gè)派生類HayesModem、USRoboticsModem和EarniesModem實(shí)現(xiàn)。它很好地遵循了OCP、LSP和DIP。當(dāng)增加新種類的調(diào)制解調(diào)器時(shí),調(diào)制解調(diào)器的客戶程序不會受影響。

    假定這種情形持續(xù)了幾年,并有許多調(diào)制解調(diào)器的客戶程序都在使用著Modem接口。現(xiàn)出現(xiàn)了一種不撥號的調(diào)制解調(diào)器,被稱為專用調(diào)制解調(diào)器。它們位于一條專用連接的兩端。有幾個(gè)新應(yīng)用程序使用這些專用調(diào)制解調(diào)器,它們無需撥號。我們稱這些使用者為DedUser。但是,客戶希望當(dāng)前所有的調(diào)制解調(diào)器客戶程序都可以使用這些專用調(diào)制解調(diào)器。他們不希望去更改許許多多的調(diào)制解調(diào)器客戶應(yīng)用程序,所以完全可以讓這些調(diào)制解調(diào)器客戶程序去撥一些假(dummy)電話號碼。

    如果能選擇的話,我們會把系統(tǒng)的設(shè)計(jì)更改為下圖所示的那樣。

    我們把撥號和通信功能分離為兩個(gè)不同的接口。原來的調(diào)制解調(diào)器實(shí)現(xiàn)這兩個(gè)接口,而調(diào)制解調(diào)器客戶程序使用這兩個(gè)接口。DedUser只使用Modem接口,而DedicateModem只實(shí)現(xiàn)Modem接口。但這樣做會要求我們更改所有的調(diào)制解調(diào)器客戶程序--這是客戶不允許的。

    一個(gè)可能的解決方案是讓DedicatedModem從Modem派生并且把dial方法和hangup方法實(shí)現(xiàn)為空,就像下面這樣:

    幾個(gè)月后,已經(jīng)有了大量的DedUser,此時(shí)客戶提出了一個(gè)新的更改。為了能撥國際電話號碼、信用卡電話、PIN標(biāo)識電話等等,必修對現(xiàn)有dial中使用char[10]存儲號碼改為能夠撥打任意長度的電話號碼。

    顯然,所有的調(diào)制解調(diào)器客戶程序都必須更改。客戶同意了對調(diào)制解調(diào)器客戶程序的更改,因?yàn)樗麄儎e無選擇。糟糕的是,現(xiàn)在必須要去告訴DedUser的編寫者,他們必須要更改他們的代碼!你可以想象他們聽到這個(gè)會有多高興。本來他們是不用調(diào)用dial的。

    這就是許多項(xiàng)目都會具有的那種有害的混亂依賴關(guān)系。系統(tǒng)某一部分中的一個(gè)雜湊體(kludge)創(chuàng)建了一個(gè)有害的依賴關(guān)系,最終導(dǎo)致系統(tǒng)中完全無關(guān)的部分出現(xiàn)問題。

    如果使用ADAPTER模式解決最初的問題的話,就可以避免這個(gè)嚴(yán)重問題。如圖:

    請注意,雜湊體仍然存在。適配器仍然要模擬連接狀態(tài)。然而,所有的依賴關(guān)系都是從適配器發(fā)起的。雜湊體和系統(tǒng)隔離,藏身于幾乎無人知曉的適配器中。

    BRIDGE模式

    看待這個(gè)問題,還有另外一個(gè)方式。現(xiàn)在,出現(xiàn)了另外一種切分Modem層次結(jié)構(gòu)的方式。如下圖:

    這不是一個(gè)理想的結(jié)構(gòu)。每當(dāng)增加一款新硬件時(shí),就必須創(chuàng)建兩個(gè)新類--一個(gè)針對專用的情況,一個(gè)針對撥號的情況。每當(dāng)增加一種新連接類型時(shí),就必須創(chuàng)建3個(gè)新類,分別對應(yīng)3款不同的硬件。如果這兩個(gè)自由度根本就是不穩(wěn)定的,那么不用多久,就會出現(xiàn)大量的派生類。

    在類型層次結(jié)構(gòu)具有多個(gè)自由度的情況中,BRIDGE模式通常是有用的。我們可以把這些層次結(jié)構(gòu)分開并通過橋把它們結(jié)合到一起,而不是把它們合并起來。如圖:

    我們把調(diào)制解調(diào)器類層次結(jié)構(gòu)分成兩個(gè)層次結(jié)構(gòu)。一個(gè)表示連接方法,另一個(gè)表示硬件。

    這個(gè)結(jié)構(gòu)雖然復(fù)雜,但是很有趣。它的創(chuàng)建不會影響到調(diào)制解調(diào)器的使用者,并且還完全分離了連接策略和硬件實(shí)現(xiàn)。ModemConnectController的每個(gè)派生類代表了一個(gè)新的連接策略。在這個(gè)策略的實(shí)現(xiàn)中可以使用sendlmp、receivelmp、diallmp和hanglmp。新imp方法的增加不會影響到使用者。可以使用ISP來給連接控制類增加新的接口。這種做法可以創(chuàng)建出一條遷移路徑,調(diào)制解調(diào)器的客戶程序可以沿著這條路徑慢慢地得到一個(gè)比dial和hangup層次更高的API。


    五、?另外一個(gè)實(shí)際應(yīng)用Bridge模式的例子

    該例子演示了業(yè)務(wù)對象(BusinessObject)通過Bridge模式與數(shù)據(jù)對象(DataObject)解耦。數(shù)據(jù)對象的實(shí)現(xiàn)可以在不改變客戶端代碼的情況下動態(tài)進(jìn)行更換。

    // ?Bridge?pattern?--?Real?World?example
    using ?System;
    using ?System.Collections;

    // ?"Abstraction"
    class ?BusinessObject
    {
    ??
    // ?Fields
    ?? private ?DataObject?dataObject;
    ??
    protected ? string ?group;

    ??
    // ?Constructors
    ?? public ?BusinessObject(? string ?group?)
    ??
    {
    ????
    this .group? = ?group;
    ??}


    ??
    // ?Properties
    ?? public ?DataObject?DataObject
    ??
    {
    ????
    set {?dataObject? = ?value;?}
    ????
    get {? return ?dataObject;?}
    ??}


    ??
    // ?Methods
    ?? virtual ? public ? void ?Next()
    ??
    {?dataObject.NextRecord();?}

    ??
    virtual ? public ? void ?Prior()
    ??
    {?dataObject.PriorRecord();?}

    ??
    virtual ? public ? void ?New(? string ?name?)
    ??
    {?dataObject.NewRecord(?name?);?}

    ??
    virtual ? public ? void ?Delete(? string ?name?)
    ??
    {?dataObject.DeleteRecord(?name?);?}

    ??
    virtual ? public ? void ?Show()
    ??
    {?dataObject.ShowRecord();?}

    ??
    virtual ? public ? void ?ShowAll()
    ??
    {
    ????Console.WriteLine(?
    " Customer?Group:?{0} " ,?group?);
    ????dataObject.ShowAllRecords();
    ??}

    }


    // ?"RefinedAbstraction"
    class ?CustomersBusinessObject?:?BusinessObject
    {
    ??
    // ?Constructors
    ?? public ?CustomersBusinessObject(? string ?group?)
    ????:?
    base (?group?) {}

    ??
    // ?Methods
    ?? override ? public ? void ?ShowAll()
    ??
    {
    ????
    // ?Add?separator?lines
    ????Console.WriteLine();
    ????Console.WriteLine(?
    " ------------------------ " ?);
    ????
    base .ShowAll();
    ????Console.WriteLine(?
    " ------------------------ " ?);
    ??}

    }


    // ?"Implementor"
    abstract ? class ?DataObject
    {
    ??
    // ?Methods
    ?? abstract ? public ? void ?NextRecord();
    ??
    abstract ? public ? void ?PriorRecord();
    ??
    abstract ? public ? void ?NewRecord(? string ?name?);
    ??
    abstract ? public ? void ?DeleteRecord(? string ?name?);
    ??
    abstract ? public ? void ?ShowRecord();
    ??
    abstract ? public ? void ?ShowAllRecords();
    }


    // ?"ConcreteImplementor"
    class ?CustomersDataObject?:?DataObject
    {
    ??
    // ?Fields
    ?? private ?ArrayList?customers? = ? new ?ArrayList();
    ??
    private ? int ?current? = ? 0 ;

    ??
    // ?Constructors
    ?? public ?CustomersDataObject()
    ??
    {
    ????
    // ?Loaded?from?a?database
    ????customers.Add(? " Jim?Jones " ?);
    ????customers.Add(?
    " Samual?Jackson " ?);
    ????customers.Add(?
    " Allen?Good " ?);
    ????customers.Add(?
    " Ann?Stills " ?);
    ????customers.Add(?
    " Lisa?Giolani " ?);
    ??}


    ??
    // ?Methods
    ?? public ? override ? void ?NextRecord()
    ??
    {
    ????
    if (?current? <= ?customers.Count? - ? 1 ?)
    ??????current
    ++ ;
    ??}


    ??
    public ? override ? void ?PriorRecord()
    ??
    {
    ????
    if (?current? > ? 0 ?)
    ??????current
    -- ;
    ??}


    ??
    public ? override ? void ?NewRecord(? string ?name?)
    ??
    {
    ????customers.Add(?name?);
    ??}


    ??
    public ? override ? void ?DeleteRecord(? string ?name?)
    ??
    {
    ????customers.Remove(?name?);
    ??}


    ??
    public ? override ? void ?ShowRecord()
    ??
    {
    ????Console.WriteLine(?customers[?current?]?);
    ??}


    ??
    public ? override ? void ?ShowAllRecords()
    ??
    {
    ????
    foreach (? string ?name? in ?customers?)
    ??????Console.WriteLine(?
    " ? " ? + ?name?);
    ??}

    }


    /// ? <summary>
    /// ?Client?test
    /// ? </summary>

    public ? class ?BusinessApp
    {
    ??
    public ? static ? void ?Main(? string []?args?)
    ??
    {
    ????
    // ?Create?RefinedAbstraction
    ????CustomersBusinessObject?customers? =
    ??????
    new ?CustomersBusinessObject( " ?Chicago? " );

    ????
    // ?Set?ConcreteImplementor
    ????customers.DataObject? = ? new ?CustomersDataObject();

    ????
    // ?Exercise?the?bridge
    ????customers.Show();
    ????customers.Next();
    ????customers.Show();
    ????customers.Next();
    ????customers.Show();
    ????customers.New(?
    " Henry?Velasquez " ?);

    ????customers.ShowAll();
    ??}

    }

    ?

    六、?在什么情況下應(yīng)當(dāng)使用橋梁模式

    根據(jù)上面的分析,在以下的情況下應(yīng)當(dāng)使用橋梁模式:

    • 如果一個(gè)系統(tǒng)需要在構(gòu)件的抽象化角色和具體化角色之間增加更多的靈活性,避免在兩個(gè)層次之間建立靜態(tài)的聯(lián)系。
    • 設(shè)計(jì)要求實(shí)現(xiàn)化角色的任何改變不應(yīng)當(dāng)影響客戶端,或者說實(shí)現(xiàn)化角色的改變對客戶端是完全透明的。
    • 一個(gè)構(gòu)件有多于一個(gè)的抽象化角色和實(shí)現(xiàn)化角色,系統(tǒng)需要它們之間進(jìn)行動態(tài)耦合。
    • 雖然在系統(tǒng)中使用繼承是沒有問題的,但是由于抽象化角色和具體化角色需要獨(dú)立變化,設(shè)計(jì)要求需要獨(dú)立管理這兩者。

    posted on 2006-09-18 13:38 Binary 閱讀(3284) 評論(2)  編輯  收藏 所屬分類: 設(shè)計(jì)模式

    評論

    # re: 一、 橋梁(Bridge)模式  回復(fù)  更多評論   

    寫的很透徹,謝謝
    2009-01-19 00:15 | yoking

    # re: 一、 橋梁(Bridge)模式  回復(fù)  更多評論   

    寫的很不錯(cuò),看了兩遍,呵呵呵
    2010-01-14 00:03 | 路過

    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 日本成年免费网站| 久久久无码精品亚洲日韩软件| 亚洲人成网站999久久久综合| 免费a级毛片大学生免费观看| 中文字幕乱码系列免费| 亚洲女人18毛片水真多| avtt亚洲天堂| 免费A级毛片无码A∨免费| 美女18毛片免费视频| 亚洲AV日韩精品久久久久| 好男人看视频免费2019中文| 成年女人A毛片免费视频| 激情综合亚洲色婷婷五月APP| 亚洲性久久久影院| 黄瓜视频影院在线观看免费| 国产日韩在线视频免费播放| 亚洲高清中文字幕免费| 亚洲人成网站在线观看播放| 卡一卡二卡三在线入口免费| 久久青草91免费观看| 美女免费视频一区二区| 亚洲伊人久久大香线蕉影院| 亚洲乱码国产乱码精品精| 午夜视频免费成人| 久久w5ww成w人免费| 一个人免费播放在线视频看片| 激情五月亚洲色图| 久久久久亚洲AV成人无码| 在线观看国产情趣免费视频| 无码精品人妻一区二区三区免费看| 亚洲AV无码国产一区二区三区| 精品亚洲成AV人在线观看| 亚洲一级特黄无码片| 在线a人片天堂免费观看高清| 99久久久国产精品免费牛牛四川 | 色片在线免费观看| 久久爰www免费人成| 国产精品美女久久久免费| 激情无码亚洲一区二区三区 | 亚洲首页在线观看| 国产亚洲成AV人片在线观黄桃|