設(shè)計(jì)模式-橋接模式(結(jié)構(gòu)型)

定義

將抽象部分與它的具體實(shí)現(xiàn)部分分離,使它們都可以獨(dú)立的變化视粮。(一定程度上解耦)

通過組合的方式建立兩個(gè)類之間的聯(lián)系细办,而不是繼承

適用場(chǎng)景

  • 抽象和具體實(shí)現(xiàn)之間增加更多的靈活性。
  • 一個(gè)類存在兩個(gè)(或多個(gè))獨(dú)立變化的維度蕾殴,且這兩個(gè)(或多個(gè))維度都需要獨(dú)立進(jìn)行擴(kuò)展笑撞。
  • 不希望使用繼承,或因?yàn)槎鄬永^承導(dǎo)致系統(tǒng)類的個(gè)數(shù)劇增钓觉。

優(yōu)點(diǎn)

  • 分離抽象部分及其具體實(shí)現(xiàn)部分茴肥。(抽象和實(shí)現(xiàn)不在同一維度)
  • 提高了系統(tǒng)可擴(kuò)展性
  • 符合開閉原則
  • 合成復(fù)用原則

缺點(diǎn)

  • 增加了系統(tǒng)和理解設(shè)計(jì)難度。
  • 需要正確的識(shí)別出系統(tǒng)兩個(gè)獨(dú)立變化的維度议谷。

代碼

橋接模式說起來很難理解炉爆,其核心就是抽象與實(shí)現(xiàn)分離使用組合的方式分離開來。我們來實(shí)現(xiàn)這么一個(gè)業(yè)務(wù)場(chǎng)景卧晓,來加深理解一下橋接模式芬首。

目前我們使用手機(jī),都有兩大主系統(tǒng)逼裆,安卓和IOS系統(tǒng)郁稍。但是這不影響我們使用微信,QQ或者其他社交軟件進(jìn)行聊天胜宇。

我們使用橋接模式來實(shí)現(xiàn)這個(gè)使用不同系統(tǒng)以及不同的社交軟件進(jìn)行聊天的業(yè)務(wù)場(chǎng)景耀怜。

首先需要進(jìn)行抽象:

  • 社交軟件
    • 打開軟件
    • 聊天功能
  • 系統(tǒng)
    • 使用系統(tǒng)打開軟件

下面我們來進(jìn)行具體的實(shí)現(xiàn)

社交軟件代碼

社交軟件抽象接口SocialSofware

public interface SocialSofware {
    /**
     * 打開軟件
     * @return
     */
    SocialSofware openSoftware();

    /**
     * 開始聊天
     */
    void chat();
}

我們的抽象已經(jīng)完成恢着,接下來,讓我們具體實(shí)現(xiàn)兩個(gè)社交軟件QQweichat

QQ軟件QQSoftware

/**
 * QQ軟件
 */
public class QQSoftware implements SocialSofware {
    @Override
    public SocialSofware openSoftware() {
        System.out.println("打開QQ");
        return new QQSoftware();
    }

    @Override
    public void chat() {
        System.out.println("使用QQ進(jìn)行聊天");
    }
}

微信軟件WeichatSoftware

/**
 * 微信軟件
 */
public class WeichatSoftware implements SocialSofware {
    @Override
    public SocialSofware openSoftware() {
        System.out.println("打開微信");
        return new WeichatSoftware();
    }

    @Override
    public void chat() {
        System.out.println("使用微信進(jìn)行聊天");
    }
}

操作系統(tǒng)代碼

抽象類操作系統(tǒng)PhoneOs

這里為什么使用抽象類呢财破,因?yàn)槲覀儗⒘奶燔浖氲讲僮飨到y(tǒng)中掰派,需要使用組合模式,讓子類來具體實(shí)現(xiàn)左痢。

/**
 * 手機(jī)操作系統(tǒng)
 */
public abstract class PhoneOs {

    /**
     * 只有子類可以調(diào)用
     */
    protected SocialSofware socialSofware;

    public PhoneOs(SocialSofware socialSofware) {
        this.socialSofware = socialSofware;
    }

    /**
     * 打開軟件
     * @return
     */
    abstract SocialSofware open();

}

蘋果操作系統(tǒng)IosPhone

/**
 * 蘋果操作系統(tǒng)
 */
public class IosPhone extends PhoneOs{

    public IosPhone(SocialSofware socialSofware) {
        super(socialSofware);
    }

    @Override
    SocialSofware open() {
        System.out.println("蘋果系統(tǒng)打開軟件");
        return socialSofware.openSoftware();
    }
}

安卓操作系統(tǒng)AndroidPhone

/**
 * 安卓手機(jī)
 */
public class AndroidPhone extends PhoneOs {
    public AndroidPhone(SocialSofware socialSofware) {
        super(socialSofware);
    }

    @Override
    SocialSofware open() {
        System.out.println("安卓系統(tǒng)打開軟件");
        return socialSofware.openSoftware();
    }
}

我們可以看到這兩個(gè)操作系統(tǒng)具體實(shí)現(xiàn)類靡羡,通過組合將社交軟件引入進(jìn)來,并且調(diào)用其打開方法進(jìn)行打開俊性,這樣無論社交軟件打開方式怎么變略步,具體實(shí)現(xiàn)類不受影響。

UML類圖

bridgeuml.jpg

代碼測(cè)試

BridgeTest

public class BridgeTest {

    public static void main(String[] args) {
        /**
         * IOS打開QQ
         */
        PhoneOs iosQQ = new IosPhone(new QQSoftware());
        QQSoftware qqSoftware = (QQSoftware) iosQQ.open();
        qqSoftware.chat();

        /**
         * 安卓打開weichat
         */
        PhoneOs androidWeiChat = new AndroidPhone(new WeichatSoftware());
        WeichatSoftware weichatSoftware = (WeichatSoftware) androidWeiChat.open();
        weichatSoftware.chat();

    }
}

我們來使用不同系統(tǒng)打開不同社交軟件看一下結(jié)果如何:

bridgeresult.jpg

我們可以看到 我們創(chuàng)建了某個(gè)系統(tǒng)并且調(diào)用了open方法來委托社交軟件來執(zhí)行openSofeware方法定页。所以我們這個(gè) 就搭建完成了趟薄。

其他源碼使用

我們來看一下java.sql.DriverManager類中的 registerDriver(java.sql.Driver, java.sql.DriverAction)方法

public static synchronized void registerDriver(java.sql.Driver driver,
        DriverAction da)
    throws SQLException {

    /* Register the driver if it has not already been added to our list */
    if(driver != null) {
        registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
    } else {
        // This is for compatibility with the original DriverManager
        throw new NullPointerException();
    }

    println("registerDriver: " + driver);

}

這個(gè)方法相當(dāng)于將每個(gè)數(shù)據(jù)庫驅(qū)動(dòng)抽象。然后通過getConnection方法來進(jìn)獲取對(duì)應(yīng)的連接典徊。

private static Connection getConnection(
    String url, java.util.Properties info, Class<?> caller) throws SQLException {
    /*
     * When callerCl is null, we should check the application's
     * (which is invoking this class indirectly)
     * classloader, so that the JDBC driver class outside rt.jar
     * can be loaded from here.
     */
    ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
    synchronized(DriverManager.class) {
        // synchronize loading of the correct classloader.
        if (callerCL == null) {
            callerCL = Thread.currentThread().getContextClassLoader();
        }
    }

    if(url == null) {
        throw new SQLException("The url cannot be null", "08001");
    }

    println("DriverManager.getConnection(\"" + url + "\")");

    // Walk through the loaded registeredDrivers attempting to make a connection.
    // Remember the first exception that gets raised so we can reraise it.
    SQLException reason = null;

    for(DriverInfo aDriver : registeredDrivers) {
        // If the caller does not have permission to load the driver then
        // skip it.
        if(isDriverAllowed(aDriver.driver, callerCL)) {
            try {
                println("    trying " + aDriver.driver.getClass().getName());
                Connection con = aDriver.driver.connect(url, info);
                if (con != null) {
                    // Success!
                    println("getConnection returning " + aDriver.driver.getClass().getName());
                    return (con);
                }
            } catch (SQLException ex) {
                if (reason == null) {
                    reason = ex;
                }
            }

        } else {
            println("    skipping: " + aDriver.getClass().getName());
        }

    }

    // if we got here nobody could connect.
    if (reason != null)    {
        println("getConnection failed: " + reason);
        throw reason;
    }

    println("getConnection: no suitable driver found for "+ url);
    throw new SQLException("No suitable driver found for "+ url, "08001");
}

小結(jié)

橋接模式與 適配器模式或者組合模式都比較相像杭煎,希望我們可以區(qū)分開來,并且適當(dāng)?shù)倪\(yùn)用卒落。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末岔帽,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子导绷,更是在濱河造成了極大的恐慌,老刑警劉巖屎飘,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件妥曲,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡钦购,警方通過查閱死者的電腦和手機(jī)檐盟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來押桃,“玉大人葵萎,你說我怎么就攤上這事〕” “怎么了羡忘?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長磕昼。 經(jīng)常有香客問我卷雕,道長,這世上最難降的妖魔是什么票从? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任漫雕,我火速辦了婚禮滨嘱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘浸间。我一直安慰自己太雨,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布魁蒜。 她就那樣靜靜地躺著囊扳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪梅惯。 梳的紋絲不亂的頭發(fā)上宪拥,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音铣减,去河邊找鬼她君。 笑死,一個(gè)胖子當(dāng)著我的面吹牛葫哗,可吹牛的內(nèi)容都是我干的缔刹。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼劣针,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼校镐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起捺典,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤鸟廓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后襟己,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體引谜,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年擎浴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了员咽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡贮预,死狀恐怖贝室,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情仿吞,我是刑警寧澤滑频,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站唤冈,受9級(jí)特大地震影響误趴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜务傲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一凉当、第九天 我趴在偏房一處隱蔽的房頂上張望枣申。 院中可真熱鬧,春花似錦看杭、人聲如沸忠藤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽模孩。三九已至,卻和暖如春贮缅,著一層夾襖步出監(jiān)牢的瞬間榨咐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來泰國打工谴供, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留块茁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓桂肌,卻偏偏與公主長得像数焊,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子崎场,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

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