java中的橋接模式

本文參考:
http://www.oschina.net/question/1436074_140456

http://design-patterns.readthedocs.io/zh_CN/latest/structural_patterns/bridge.html

一、模式動(dòng)機(jī)

設(shè)想如果要繪制矩形您炉、圓形多望、橢圓闸餐、正方形丛晌,我們至少需要4個(gè)形狀類,但是如果繪制的圖形需要具有不同的顏色,如紅色哗讥、綠色、藍(lán)色等胞枕,此時(shí)至少有如下兩種設(shè)計(jì)方案:

  • 第一種設(shè)計(jì)方案是為每一種形狀都提供一套各種顏色的版本杆煞。
  • 第二種設(shè)計(jì)方案是根據(jù)實(shí)際需要對形狀和顏色進(jìn)行組合

對于有兩個(gè)變化維度(即兩個(gè)變化的原因)的系統(tǒng),采用方案二來進(jìn)行設(shè)計(jì)系統(tǒng)中類的個(gè)數(shù)更少腐泻,且系統(tǒng)擴(kuò)展更為方便决乎。設(shè)計(jì)方案二即是橋接模式的應(yīng)用。橋接模式將繼承關(guān)系轉(zhuǎn)換為關(guān)聯(lián)關(guān)系派桩,從而降低了類與類之間的耦合构诚,減少了代碼編寫量。

二铆惑、模式定義

橋接模式(Bridge Pattern):將抽象部分與它的實(shí)現(xiàn)部分分離范嘱,使它們都可以獨(dú)立地變化。它是一種對象結(jié)構(gòu)型模式员魏,又稱為柄體(Handle and Body)模式或接口(Interface)模式丑蛤。

三、模式結(jié)構(gòu)

橋接模式包含如下角色:

  • Abstraction:抽象類撕阎,抽象部分的接口受裹。通常在這個(gè)對象里面,要維護(hù)一個(gè)實(shí)現(xiàn)部分的對象引用闻书,在抽象對象里面的方法名斟,需要調(diào)用實(shí)現(xiàn)部分的對象來完成。這個(gè)對象里面的方法魄眉,通常都是跟具體的業(yè)務(wù)相關(guān)的方法砰盐。
  • RefinedAbstraction:擴(kuò)充抽象類,擴(kuò)展抽象部分的接口坑律,通常在這些對象里面岩梳,定義跟實(shí)際業(yè)務(wù)相關(guān)的方法,這些方法的實(shí)現(xiàn)通常會(huì)使用Abstraction中定義的方法晃择,也可能需要調(diào)用實(shí)現(xiàn)部分的對象來完成冀值。
  • Implementor:實(shí)現(xiàn)類接口,定義實(shí)現(xiàn)部分的接口宫屠,這個(gè)接口不用和Abstraction里面的方法一致列疗,通常是由Implementor接口提供基本的操作,而Abstraction里面定義的是基于這些基本操作的業(yè)務(wù)方法浪蹂,也就是說Abstraction定義了基于這些基本操作的較高層次的操作抵栈。
  • ConcreteImplementor:具體實(shí)現(xiàn)類告材,真正實(shí)現(xiàn)Implementor接口的對象。
bridge.jpg

四古劲、代碼分析

其實(shí)就是一個(gè)排列組合的過程斥赋,將需要發(fā)送的消息類型和發(fā)送的類型進(jìn)行組合,如果每個(gè)組合形式都要定義一個(gè)類的話产艾,會(huì)顯得很冗余疤剑,通過橋接模式就可以很簡潔。

定義發(fā)送方式:

public interface MessageImplementor {
    public void send(String message,String toUser);
}
public class MessageMobile implements MessageImplementor {
    @Override
    public void send(String message, String toUser) {
        System.out.println("使用手機(jī)短消息的方式闷堡,發(fā)送消息'" + message + "'給" + toUser);
    }
}

public class MessageSMS implements MessageImplementor {
    @Override
    public void send(String message, String toUser) {
        System.out.println("使用站內(nèi)短消息的方式隘膘,發(fā)送消息'" + message + "'給" + toUser);
    }
}

public class MessageEmail implements MessageImplementor {

    @Override
    public void send(String message, String toUser) {
        System.out.println("使用Email的方式,發(fā)送消息'" + message + "'給" + toUser);
    }
}

定義消息類:

public abstract class AbstractMessage {
    protected MessageImplementor impl;

    public AbstractMessage(MessageImplementor impl) {
        this.impl = impl;
    }

    public void sendMessage(String message, String toUser) {
        this.impl.send(message, toUser);
    }
}

public class CommonMessage extends AbstractMessage {
    public CommonMessage(MessageImplementor impl) {
        super(impl);
    }

    public void sendMessage(String message, String toUser) {
        //對于普通消息缚窿,什么都不干棘幸,直接調(diào)父類的方法,把消息發(fā)送出去就可以了
        super.sendMessage(message, toUser);
    }
}

public class SpecialUrgencyMessage extends AbstractMessage {

    public SpecialUrgencyMessage(MessageImplementor impl) {
        super(impl);
    }

    public void hurry(String messageId) {
        //執(zhí)行催促的業(yè)務(wù)倦零,發(fā)出催促的信息
    }

    public void sendMessage(String message, String toUser) {
        message = "特急:" + message;
        super.sendMessage(message, toUser);
        //還需要增加一條待催促的信息
    }
}

public class UrgencyMessage extends AbstractMessage {
    public UrgencyMessage(MessageImplementor impl) {
        super(impl);
    }

    public void sendMessage(String message, String toUser) {
        message = "加急:" + message;
        super.sendMessage(message, toUser);
    }

    public Object watch(String messageId) {
        //獲取相應(yīng)的數(shù)據(jù),組織成監(jiān)控的數(shù)據(jù)對象吨悍,然后返回
        return null;

    }
}

測試代碼:

public class Client {
    public static void main(String[] args) {

        //創(chuàng)建具體的實(shí)現(xiàn)對象
        MessageImplementor impl = new MessageSMS();

        //創(chuàng)建一個(gè)普通消息對象
        AbstractMessage m = new CommonMessage(impl);
        m.sendMessage("請喝一杯茶", "小李");

        //創(chuàng)建一個(gè)緊急消息對象
        m = new UrgencyMessage(impl);
        m.sendMessage("請喝一杯茶", "小李");

        //創(chuàng)建一個(gè)特急消息對象
        m = new SpecialUrgencyMessage(impl);
        m.sendMessage("請喝一杯茶", "小李");

        //把實(shí)現(xiàn)方式切換成手機(jī)短消息扫茅,然后再實(shí)現(xiàn)一遍
        impl = new MessageMobile();
        m = new CommonMessage(impl);
        m.sendMessage("請喝一杯茶", "小李");
        m = new UrgencyMessage(impl);
        m.sendMessage("請喝一杯茶", "小李");
        m = new SpecialUrgencyMessage(impl);
        m.sendMessage("請喝一杯茶", "小李");
    }
}

返回結(jié)果:

使用站內(nèi)短消息的方式,發(fā)送消息'請喝一杯茶'給小李
使用站內(nèi)短消息的方式育瓜,發(fā)送消息'加急:請喝一杯茶'給小李
使用站內(nèi)短消息的方式葫隙,發(fā)送消息'特急:請喝一杯茶'給小李
使用手機(jī)短消息的方式,發(fā)送消息'請喝一杯茶'給小李
使用手機(jī)短消息的方式躏仇,發(fā)送消息'加急:請喝一杯茶'給小李
使用手機(jī)短消息的方式恋脚,發(fā)送消息'特急:請喝一杯茶'給小李

五、模式分析

理解橋接模式焰手,重點(diǎn)需要理解如何將抽象化(Abstraction)與實(shí)現(xiàn)化(Implementation)脫耦糟描,使得二者可以獨(dú)立地變化。

  • 抽象化:抽象化就是忽略一些信息书妻,把不同的實(shí)體當(dāng)作同樣的實(shí)體對待船响。在面向?qū)ο笾校瑢ο蟮墓餐再|(zhì)抽取出來形成類的過程即為抽象化的過程躲履。
  • 實(shí)現(xiàn)化:針對抽象化給出的具體實(shí)現(xiàn)见间,就是實(shí)現(xiàn)化,抽象化與實(shí)現(xiàn)化是一對互逆的概念工猜,實(shí)現(xiàn)化產(chǎn)生的對象比抽象化更具體米诉,是對抽象化事物的進(jìn)一步具體化的產(chǎn)物。
  • 脫耦:脫耦就是將抽象化和實(shí)現(xiàn)化之間的耦合解脫開篷帅,或者說是將它們之間的強(qiáng)關(guān)聯(lián)改換成弱關(guān)聯(lián)史侣,將兩個(gè)角色之間的繼承關(guān)系改為關(guān)聯(lián)關(guān)系拴泌。橋接模式中的所謂脫耦,就是指在一個(gè)軟件系統(tǒng)的抽象化和實(shí)現(xiàn)化之間使用關(guān)聯(lián)關(guān)系(組合或者聚合關(guān)系)而不是繼承關(guān)系抵窒,從而使兩者可以相對獨(dú)立地變化弛针,這就是橋接模式的用意。

六李皇、優(yōu)點(diǎn)

橋接模式的優(yōu)點(diǎn):

  • 分離抽象接口及其實(shí)現(xiàn)部分削茁。
  • 橋接模式有時(shí)類似于多繼承方案,但是多繼承方案違背了類的單一職責(zé)原則(即一個(gè)類只有一個(gè)變化的原因)掉房,復(fù)用性比較差茧跋,而且多繼承結(jié)構(gòu)中類的個(gè)數(shù)非常龐大,橋接模式是比多繼承方案更好的解決方法卓囚。
  • 橋接模式提高了系統(tǒng)的可擴(kuò)充性瘾杭,在兩個(gè)變化維度中任意擴(kuò)展一個(gè)維度,都不需要修改原有系統(tǒng)哪亿。
  • 實(shí)現(xiàn)細(xì)節(jié)對客戶透明粥烁,可以對用戶隱藏實(shí)現(xiàn)細(xì)節(jié)。

七蝇棉、缺點(diǎn)

橋接模式的缺點(diǎn):

  • 橋接模式的引入會(huì)增加系統(tǒng)的理解與設(shè)計(jì)難度讨阻,由于聚合關(guān)聯(lián)關(guān)系建立在抽象層,要求開發(fā)者針對抽象進(jìn)行設(shè)計(jì)與編程篡殷。
  • 橋接模式要求正確識別出系統(tǒng)中兩個(gè)獨(dú)立變化的維度钝吮,因此其使用范圍具有一定的局限性。

八板辽、適用環(huán)境

在以下情況下可以使用橋接模式:

  • 如果一個(gè)系統(tǒng)需要在構(gòu)件的抽象化角色和具體化角色之間增加更多的靈活性奇瘦,避免在兩個(gè)層次之間建立靜態(tài)的繼承聯(lián)系,通過橋接模式可以使它們在抽象層建立一個(gè)關(guān)聯(lián)關(guān)系劲弦。
  • 抽象化角色和實(shí)現(xiàn)化角色可以以繼承的方式獨(dú)立擴(kuò)展而互不影響耳标,在程序運(yùn)行時(shí)可以動(dòng)態(tài)將一個(gè)抽象化子類的對象和一個(gè)實(shí)現(xiàn)化子類的對象進(jìn)行組合,即系統(tǒng)需要對抽象化角色和實(shí)現(xiàn)化角色進(jìn)行動(dòng)態(tài)耦合瓶您。
  • 一個(gè)類存在兩個(gè)獨(dú)立變化的維度麻捻,且這兩個(gè)維度都需要進(jìn)行擴(kuò)展。
  • 雖然在系統(tǒng)中使用繼承是沒有問題的呀袱,但是由于抽象化角色和具體化角色需要獨(dú)立變化贸毕,設(shè)計(jì)要求需要獨(dú)立管理這兩者。
  • 對于那些不希望使用繼承或因?yàn)槎鄬哟卫^承導(dǎo)致系統(tǒng)類的個(gè)數(shù)急劇增加的系統(tǒng)夜赵,橋接模式尤為適用明棍。

九、模式擴(kuò)展

適配器模式與橋接模式的聯(lián)用:

  • 橋接模式和適配器模式用于設(shè)計(jì)的不同階段寇僧,橋接模式用于系統(tǒng)的初步設(shè)計(jì)摊腋,對于存在兩個(gè)獨(dú)立變化維度的類可以將其分為抽象化和實(shí)現(xiàn)化兩個(gè)角色沸版,使它們可以分別進(jìn)行變化;而在初步設(shè)計(jì)完成之后兴蒸,當(dāng)發(fā)現(xiàn)系統(tǒng)與已有類無法協(xié)同工作時(shí)视粮,可以采用適配器模式。但有時(shí)候在設(shè)計(jì)初期也需要考慮適配器模式橙凳,特別是那些涉及到大量第三方應(yīng)用接口的情況蕾殴。

十、總結(jié)

  • 橋接模式將抽象部分與它的實(shí)現(xiàn)部分分離岛啸,使它們都可以獨(dú)立地變化钓觉。它是一種對象結(jié)構(gòu)型模式,又稱為柄體(Handle and Body)模式或接口(Interface)模式坚踩。
  • 橋接模式包含如下四個(gè)角色:抽象類中定義了一個(gè)實(shí)現(xiàn)類接口類型的對象并可以維護(hù)該對象荡灾;擴(kuò)充抽象類擴(kuò)充由抽象類定義的接口,它實(shí)現(xiàn)了在抽象類中定義的抽象業(yè)務(wù)方法瞬铸,在擴(kuò)充抽象類中可以調(diào)用在實(shí)現(xiàn)類接口中定義的業(yè)務(wù)方法批幌;實(shí)現(xiàn)類接口定義了實(shí)現(xiàn)類的接口,實(shí)現(xiàn)類接口僅提供基本操作嗓节,而抽象類定義的接口可能會(huì)做更多更復(fù)雜的操作逼裆;具體實(shí)現(xiàn)類實(shí)現(xiàn)了實(shí)現(xiàn)類接口并且具體實(shí)現(xiàn)它,在不同的具體實(shí)現(xiàn)類中提供基本操作的不同實(shí)現(xiàn)赦政,在程序運(yùn)行時(shí),具體實(shí)現(xiàn)類對象將替換其父類對象耀怜,提供給客戶端具體的業(yè)務(wù)操作方法恢着。
  • 在橋接模式中,抽象化(Abstraction)與實(shí)現(xiàn)化(Implementation)脫耦财破,它們可以沿著各自的維度獨(dú)立變化掰派。
  • 橋接模式的主要優(yōu)點(diǎn)是分離抽象接口及其實(shí)現(xiàn)部分,是比多繼承方案更好的解決方法左痢,橋接模式還提高了系統(tǒng)的可擴(kuò)充性靡羡,在兩個(gè)變化維度中任意擴(kuò)展一個(gè)維度,都不需要修改原有系統(tǒng)俊性,實(shí)現(xiàn)細(xì)節(jié)對客戶透明略步,可以對用戶隱藏實(shí)現(xiàn)細(xì)節(jié);其主要缺點(diǎn)是增加系統(tǒng)的理解與設(shè)計(jì)難度定页,且識別出系統(tǒng)中兩個(gè)獨(dú)立變化的維度并不是一件容易的事情趟薄。
  • 橋接模式適用情況包括:需要在構(gòu)件的抽象化角色和具體化角色之間增加更多的靈活性,避免在兩個(gè)層次之間建立靜態(tài)的繼承聯(lián)系典徊;抽象化角色和實(shí)現(xiàn)化角色可以以繼承的方式獨(dú)立擴(kuò)展而互不影響杭煎;一個(gè)類存在兩個(gè)獨(dú)立變化的維度恩够,且這兩個(gè)維度都需要進(jìn)行擴(kuò)展;設(shè)計(jì)要求需要獨(dú)立管理抽象化角色和具體化角色羡铲;不希望使用繼承或因?yàn)槎鄬哟卫^承導(dǎo)致系統(tǒng)類的個(gè)數(shù)急劇增加的系統(tǒng)蜂桶。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市也切,隨后出現(xiàn)的幾起案子扑媚,更是在濱河造成了極大的恐慌,老刑警劉巖贾费,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钦购,死亡現(xiàn)場離奇詭異,居然都是意外死亡褂萧,警方通過查閱死者的電腦和手機(jī)押桃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來导犹,“玉大人唱凯,你說我怎么就攤上這事』蚜。” “怎么了磕昼?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長节猿。 經(jīng)常有香客問我票从,道長,這世上最難降的妖魔是什么滨嘱? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任峰鄙,我火速辦了婚禮,結(jié)果婚禮上太雨,老公的妹妹穿的比我還像新娘吟榴。我一直安慰自己,他們只是感情好囊扳,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布吩翻。 她就那樣靜靜地躺著,像睡著了一般锥咸。 火紅的嫁衣襯著肌膚如雪狭瞎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天她君,我揣著相機(jī)與錄音脚作,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛球涛,可吹牛的內(nèi)容都是我干的劣针。 我是一名探鬼主播,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼亿扁,長吁一口氣:“原來是場噩夢啊……” “哼捺典!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起从祝,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤襟己,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后牍陌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體擎浴,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年毒涧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了贮预。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,427評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡契讲,死狀恐怖仿吞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情捡偏,我是刑警寧澤唤冈,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站银伟,受9級特大地震影響你虹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜彤避,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一售葡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧忠藤,春花似錦、人聲如沸楼雹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽贮缅。三九已至榨咐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谴供,已是汗流浹背块茁。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人数焊。 一個(gè)月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓永淌,卻偏偏與公主長得像,于是被迫代替她去往敵國和親佩耳。 傳聞我的和親對象是個(gè)殘疾皇子遂蛀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 1 場景問題# 1.1 發(fā)送提示消息## 考慮這樣一個(gè)實(shí)際的業(yè)務(wù)功能:發(fā)送提示消息「珊瘢基本上所有帶業(yè)務(wù)流程處理的系統(tǒng)...
    七寸知架構(gòu)閱讀 5,017評論 5 63
  • 設(shè)計(jì)模式匯總 一李滴、基礎(chǔ)知識 1. 設(shè)計(jì)模式概述 定義:設(shè)計(jì)模式(Design Pattern)是一套被反復(fù)使用、多...
    MinoyJet閱讀 3,948評論 1 15
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法蛮瞄,類相關(guān)的語法所坯,內(nèi)部類的語法,繼承相關(guān)的語法挂捅,異常的語法芹助,線程的語...
    子非魚_t_閱讀 31,660評論 18 399
  • 在正式介紹橋接模式之前,我先跟大家談?wù)剝煞N常見文具的區(qū)別籍凝,它們是毛筆和蠟筆周瞎。假如我們需要大中小3種型號的畫筆,能夠...
    justCode_閱讀 1,772評論 0 7
  • 第二次分享完斷舍離饵蒂,在這個(gè)時(shí)間點(diǎn)里糾結(jié)到底做什么好声诸,是寫作還是看電影?最終傾向于寫作了退盯,在這個(gè)安靜的晚上彼乌。隨即,...
    梅子Mey閱讀 607評論 0 2