設(shè)計(jì)模式-橋接模式(Bridge Pattern)

一火本、橋接模式(Bridge Pattern)

在現(xiàn)實(shí)生活中灭贷,某些類具有兩個(gè)或多個(gè)維度的變化温学,如圖形既可按形狀分,又可按顏色分甚疟。如何設(shè)計(jì)類似于 Photoshop 這樣的軟件仗岖,能畫不同形狀和不同顏色的圖形呢?如果用繼承方式览妖,m 種形狀和 n 種顏色的圖形就有 m×n 種轧拄,不但對(duì)應(yīng)的子類很多,而且擴(kuò)展困難讽膏。

當(dāng)然檩电,這樣的例子還有很多,如不同顏色和字體的文字府树、不同品牌和功率的汽車俐末、不同性別和職業(yè)的男女、支持不同平臺(tái)和不同文件格式的媒體播放器等奄侠。如果用橋接模式就能很好地解決這些問(wèn)題卓箫。

1. 什么是橋接模式

橋接(Bridge)模式的定義如下:將抽象與實(shí)現(xiàn)分離,使它們可以獨(dú)立變化垄潮。它是用組合關(guān)系代替繼承關(guān)系來(lái)實(shí)現(xiàn)烹卒,從而降低了抽象和實(shí)現(xiàn)這兩個(gè)可變維度的耦合度。

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

  • 由于抽象與實(shí)現(xiàn)分離弯洗,所以擴(kuò)展能力強(qiáng)旅急;
  • 其實(shí)現(xiàn)細(xì)節(jié)對(duì)客戶透明。

缺點(diǎn)是:由于聚合關(guān)系建立在抽象層牡整,要求開發(fā)者針對(duì)抽象化進(jìn)行設(shè)計(jì)與編程藐吮,這增加了系統(tǒng)的理解與設(shè)計(jì)難度。

2. 橋接模式的優(yōu)缺點(diǎn)

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

  1. 分離抽象部分及其實(shí)現(xiàn)部分,提供了比集成更好解決方案炎码;
  2. 提高了系統(tǒng)的可擴(kuò)展性盟迟,某種程度上可以避免子類爆炸
  3. 符合開閉原則
  4. 符合合成復(fù)用原則秋泳,通過(guò)組合方式實(shí)現(xiàn)關(guān)聯(lián)

缺點(diǎn):

  1. 增加了系統(tǒng)的理解與設(shè)計(jì)難度潦闲,由于聚合關(guān)聯(lián)關(guān)系建立在抽象層,要求開發(fā)者針對(duì)抽象進(jìn)行設(shè)計(jì)和編程
  2. 需要正確地識(shí)別出系統(tǒng)中兩個(gè)獨(dú)立變化的緯度迫皱,因此其使用范圍具有一定的局限性

3. 橋接模式的適用場(chǎng)景

  1. 如果一個(gè)系統(tǒng)需要再構(gòu)建的抽象化角色和具體化角色之間增加更多的靈活性歉闰,避免在兩個(gè)層次之間建立靜態(tài)的繼承聯(lián)系,通過(guò)橋接模式可以使他們?cè)诔橄髮咏⒁粋€(gè)關(guān)聯(lián)關(guān)系
  2. 對(duì)于那些不希望使用繼承或因?yàn)槎鄬哟卫^承導(dǎo)致類的個(gè)數(shù)急劇增加的系統(tǒng)卓起,橋接模式尤為適用和敬;
  3. 一個(gè)類存在兩個(gè)(或多個(gè))獨(dú)立變化的緯度,且這兩個(gè)(或多個(gè))緯度都需要獨(dú)立進(jìn)行擴(kuò)展
  4. 不希望使用繼承戏阅,或因?yàn)槎鄬永^承導(dǎo)致系統(tǒng)類的個(gè)數(shù)劇增

4. 相關(guān)設(shè)計(jì)模式

橋接模式與組合模式的區(qū)別

  1. 組合模式:強(qiáng)調(diào)部分與整體的組合
  2. 橋接模式:強(qiáng)調(diào)平行類之間的組合

橋接模式與適配器模式的區(qū)別

  1. 適配器:改變已有接口昼弟,使他們相互配合,把功能相似但接口不同的類適配起來(lái)
  2. 橋接:類的抽象和實(shí)現(xiàn)分離開奕筐,目的就是分離舱痘,讓多個(gè)類能夠自由組合
  3. 二者的共同點(diǎn)是這兩個(gè)模式都是為了讓兩個(gè)類配合工作,但二者目的不同

二离赫、橋接模式的結(jié)構(gòu)與實(shí)現(xiàn)

可以將抽象化部分與實(shí)現(xiàn)化部分分開芭逝,取消二者的繼承關(guān)系,改用組合關(guān)系渊胸。

1. 橋接模式的結(jié)構(gòu)

橋接(Bridge)模式包含以下主要角色旬盯。

  1. 抽象化(Abstraction)角色:定義抽象類,并包含一個(gè)對(duì)實(shí)現(xiàn)化對(duì)象的引用翎猛。
  2. 擴(kuò)展抽象化(Refined Abstraction)角色:是抽象化角色的子類胖翰,實(shí)現(xiàn)父類中的業(yè)務(wù)方法,并通過(guò)組合關(guān)系調(diào)用實(shí)現(xiàn)化角色中的業(yè)務(wù)方法切厘。
  3. 實(shí)現(xiàn)化(Implementor)角色:定義實(shí)現(xiàn)化角色的接口萨咳,供擴(kuò)展抽象化角色調(diào)用。
  4. 具體實(shí)現(xiàn)化(Concrete Implementor)角色:給出實(shí)現(xiàn)化角色接口的具體實(shí)現(xiàn)迂卢。

其結(jié)構(gòu)圖如圖 1 所示某弦。


3-1Q115125253H1.gif

2. 橋接模式的實(shí)現(xiàn)

橋接模式的實(shí)現(xiàn)步驟

  1. 定義實(shí)現(xiàn)化角色接口 Implementor
  2. 定義具體實(shí)現(xiàn)化角色類 ConcreteImplementorA、ConcreteImplementorB
  3. 定義抽象化角色抽象類 Abstraction而克,以組合方式關(guān)聯(lián)實(shí)現(xiàn)化角色接口
  4. 定義擴(kuò)展抽象化角色類 RefinedAbstraction
  5. 編寫客戶端類 BridgePatternTest靶壮,調(diào)用具體實(shí)現(xiàn)化角色類、擴(kuò)展抽象化角色類

實(shí)現(xiàn)代碼示例:

  1. 定義實(shí)現(xiàn)化角色接口 Implementor

    /**
     * Implementor - 實(shí)現(xiàn)化角色
     * 實(shí)現(xiàn)化(Implementor)角色:定義實(shí)現(xiàn)化角色的接口员萍,供擴(kuò)展抽象化角色調(diào)用
     *
     * @author dongrui
     * @date 2020/2/25 11:03
     */
    public interface Implementor {
        void operationImpl();
    }
    
  2. 定義具體實(shí)現(xiàn)化角色類 ConcreteImplementorA腾降、ConcreteImplementorB

    /**
     * ConcreteImplementorA - 具體實(shí)現(xiàn)化角色 A
     * 具體實(shí)現(xiàn)化(Concrete Implementor)角色:給出實(shí)現(xiàn)化角色接口的具體實(shí)現(xiàn)
     *
     * @author dongrui
     * @date 2020/2/25 11:05
     */
    public class ConcreteImplementorA implements Implementor{
        @Override
        public void operationImpl() {
            System.out.println("使用 A 方式實(shí)現(xiàn)");
        }
    }
    
    /**
     * ConcreteImplementorB
     * 具體實(shí)現(xiàn)化(Concrete Implementor)角色:給出實(shí)現(xiàn)化角色接口的具體實(shí)現(xiàn)
     *
     * @author dongrui
     * @date 2020/2/25 11:08
     */
    public class ConcreteImplementorB implements Implementor {
        @Override
        public void operationImpl() {
            System.out.println("使用 B 方式實(shí)現(xiàn)");
        }
    }
    
  3. 定義抽象化角色抽象類 Abstraction,以組合方式關(guān)聯(lián)實(shí)現(xiàn)化角色接口

    /**
     * Abstraction - 抽象化角色
     * 抽象化(Abstraction)角色:定義抽象類碎绎,并包含一個(gè)對(duì)實(shí)現(xiàn)化對(duì)象的引用
     *
     * @author dongrui
     * @date 2020/2/25 11:09
     */
    public abstract class Abstraction {
        //使用組合方式關(guān)聯(lián)實(shí)現(xiàn)化角色
        protected Implementor implementor;
    
        protected Abstraction(Implementor implementor) {
            this.implementor = implementor;
        }
    
        /**
         * 供客戶端調(diào)用的業(yè)務(wù)方法
         */
        abstract void operation();
    }
    
  4. 定義擴(kuò)展抽象化角色類 RefinedAbstraction

    /**
     * RefinedAbstraction - 擴(kuò)展抽象化角色螃壤,實(shí)現(xiàn)父類中的業(yè)務(wù)方法
     * 擴(kuò)展抽象化(Refined Abstraction)角色:是抽象化角色的子類抗果,實(shí)現(xiàn)父類中的業(yè)務(wù)方法,
     * 并通過(guò)組合關(guān)系調(diào)用實(shí)現(xiàn)化角色中的業(yè)務(wù)方法奸晴。
     *
     * @author dongrui
     * @date 2020/2/25 11:12
     */
    public class RefinedAbstraction extends Abstraction {
        public RefinedAbstraction(Implementor implementor) {
            super(implementor);
        }
    
        /**
         * 供客戶端調(diào)用的業(yè)務(wù)方法
         */
        @Override
        void operation() {
            System.out.println(this.implementor.getClass());
            this.implementor.operationImpl();
        }
    }
    
  5. 編寫客戶端類 BridgePatternTest冤馏,調(diào)用具體實(shí)現(xiàn)化角色類、擴(kuò)展抽象化角色類

    /**
     * BridgePatternTest - 客戶端類
     *
     * @author dongrui
     * @date 2020/2/25 11:17
     */
    public class BridgePatternTest {
        public static void main(String[] args) {
            Implementor implementorA = new ConcreteImplementorA();
            Implementor implementorB = new ConcreteImplementorB();
    
            Abstraction abs = new RefinedAbstraction(implementorA);
    
            abs.operation();
        }
    }
    

三寄啼、橋接模式的案例實(shí)戰(zhàn)

1. 案例1—銀行存款

銀行存款業(yè)務(wù)場(chǎng)景:小張有一筆錢想用于理財(cái)投資逮光,為此做了一番功課了解到,現(xiàn)在有中國(guó)工商銀行墩划、中國(guó)農(nóng)業(yè)銀行兩家銀行涕刚,每家銀行都提供了活期存儲(chǔ)和定期存款,活期存款存取靈活但利息低乙帮,定期存款利息相對(duì)較高但存取不夠靈活杜漠,同時(shí)了解到中國(guó)工商銀行的定期存款利率相對(duì)較高,中國(guó)農(nóng)業(yè)銀行的活期存款利率相對(duì)較高察净,于是小張計(jì)劃將投資款項(xiàng)分為2部分驾茴,一部分存儲(chǔ)到中國(guó)工商銀行的定期賬戶,一部分存儲(chǔ)到中國(guó)農(nóng)業(yè)銀行的活期賬戶塞绿。

請(qǐng)根據(jù)以上業(yè)務(wù)設(shè)計(jì)一個(gè)銀行存款系統(tǒng)沟涨,提供靈活的配置功能。

1.1 業(yè)務(wù)場(chǎng)景分析

從業(yè)務(wù)場(chǎng)景可以知道异吻,有多家銀行裹赴,每家銀行都有自己的定期和活期賬戶,而客戶可以對(duì)銀行诀浪、存款類型做隨機(jī)組合棋返,因此,這種多緯度組合的場(chǎng)景非常適合使用橋接模式解決雷猪。

橋接模式的核心是將抽象與實(shí)現(xiàn)分離睛竣,使他們可以獨(dú)立變化,在該模式中求摇,活期存款射沟、定期存款是銀行存款的最終實(shí)現(xiàn)部分,是橋接模式的實(shí)現(xiàn)部分与境,中國(guó)工商銀行验夯、中國(guó)農(nóng)業(yè)銀行等銀行是抽象部分,不提供實(shí)現(xiàn)操作摔刁,通過(guò)組合存款賬戶方式實(shí)現(xiàn)存款的實(shí)現(xiàn)操作挥转。

因此,結(jié)合橋接模式設(shè)計(jì)銀行存款:

  1. 定義實(shí)現(xiàn):存款賬戶是實(shí)現(xiàn)部分,抽象出存款賬戶類為實(shí)現(xiàn)化接口绑谣,活期存儲(chǔ)党窜、定期存款為其具體實(shí)現(xiàn)
  2. 定義抽象:銀行是抽象部分,抽象出銀行類為抽象類借宵,以成員屬性方式組合存儲(chǔ)賬戶幌衣,中國(guó)工商銀行、中國(guó)農(nóng)業(yè)銀行為其擴(kuò)展實(shí)現(xiàn)
  3. 定義客戶端:在客戶端類中選擇具體賬戶和具體銀行暇务,實(shí)現(xiàn)存款業(yè)務(wù)邏輯

1.2 UML類圖

image-20200225195718522.png

1.3 代碼實(shí)現(xiàn)示例

代碼實(shí)現(xiàn)步驟:

  1. 定義存款賬戶接口
  2. 定義活期存款賬戶實(shí)現(xiàn)類泼掠、活期存款賬戶實(shí)現(xiàn)類怔软,都實(shí)現(xiàn)存款賬戶接口并重寫接口的方法
  3. 定義銀行抽象類垦细,將存款賬戶作為成員屬性,實(shí)現(xiàn)對(duì)存款操作的組合方式調(diào)用
  4. 定義中國(guó)工商銀行挡逼、中國(guó)農(nóng)業(yè)銀行的擴(kuò)展類括改,實(shí)現(xiàn)具體的存款操作
  5. 定義客戶端測(cè)試類,選擇中國(guó)工商銀行存儲(chǔ)定期存款家坎,選擇中國(guó)農(nóng)業(yè)銀行存儲(chǔ)活期存款

代碼實(shí)現(xiàn)示例:

  1. 定義存款賬戶接口

    /**
     * Account - 賬戶接口
     *
     * @author dongrui
     * @date 2020/2/20 16:20
     */
    public interface Account {
        void saveMoney(Double money);
        void printAccountType();
    }
    
  1. 定義活期存款賬戶實(shí)現(xiàn)類嘱能、活期存款賬戶實(shí)現(xiàn)類,都實(shí)現(xiàn)存款賬戶接口并重寫接口的方法

    /**
     * DepositAccount - 定期存款賬戶
     *
     * @author dongrui
     * @date 2020/2/20 16:23
     */
    public class DepositAccount implements Account {
        public void saveMoney(Double money) {
            System.out.println("打開定期賬號(hào)");
            System.out.printf("存款:%f 元\n", money);
        }
    
        public void printAccountType() {
            System.out.println("這是一個(gè)定期賬號(hào)");
        }
    }
    
    /**
     * SavingsAccount - 活期存儲(chǔ)賬戶
     *
     * @author dongrui
     * @date 2020/2/20 16:24
     */
    public class SavingsAccount implements Account {
        public void saveMoney(Double money) {
            System.out.println("打開活期賬號(hào)");
            System.out.printf("存款:%f 元\n", money);
        }
    
        public void printAccountType() {
            System.out.println("這是一個(gè)活期賬號(hào)");
        }
    }
    
  1. 定義銀行抽象類虱疏,將存款賬戶作為成員屬性惹骂,實(shí)現(xiàn)對(duì)存款操作的組合方式調(diào)用

    /**
     * Bank - 銀行抽象類,以組合方式調(diào)用存款賬戶接口
     *
     * @author dongrui
     * @date 2020/2/20 16:25
     */
    public abstract class Bank {
        protected Account account;
    
        public Bank(Account account) {
            this.account = account;
        }
    
        abstract void saveMoney(Double money);
    }
    
  1. 定義中國(guó)工商銀行做瞪、中國(guó)農(nóng)業(yè)銀行的擴(kuò)展類对粪,實(shí)現(xiàn)具體的存款操作

    /**
     * ICBCBank
     *
     * @author dongrui
     * @date 2020/2/20 16:27
     */
    public class ICBCBank extends Bank {
        public ICBCBank(Account account) {
            super(account);
        }
    
        void saveMoney(Double money) {
            System.out.println("打開中國(guó)工商銀行賬號(hào)");
            this.account.saveMoney(money);
        }
    }
    
    /**
     * ABCBank
     *
     * @author dongrui
     * @date 2020/2/20 16:26
     */
    public class ABCBank extends Bank {
        public ABCBank(Account account) {
            super(account);
        }
    
        void saveMoney(Double money) {
            System.out.println("打開中國(guó)農(nóng)業(yè)銀行賬號(hào)");
            account.saveMoney(money);
        }
    }
    
  1. 定義客戶端測(cè)試類,選擇中國(guó)工商銀行存儲(chǔ)定期存款装蓬,選擇中國(guó)農(nóng)業(yè)銀行存儲(chǔ)活期存款

    public class BankSavingsTest {
    
        public static void main(String[] args) {
            //定期賬號(hào)和活期賬號(hào)
            Account depositAccount = new DepositAccount();
            Account savingsAccount = new SavingsAccount();
            //工商銀行定期賬號(hào)
            Bank icbc = new ICBCBank(depositAccount);
            icbc.saveMoney(20000.00);
            System.out.println("------");
            //農(nóng)業(yè)銀行活期賬號(hào)
            Bank abc = new ABCBank(savingsAccount);
            abc.saveMoney(3000.00);
        }
    }
    

附錄

參考資料:

  1. 橋接模式(Bridge模式)詳解 : http://c.biancheng.net/view/1364.html
  2. 橋接模式 : https://www.runoob.com/w3cnote/bridge-pattern2.html
  3. 設(shè)計(jì)模式讀書筆記-----橋接模式: https://www.cnblogs.com/chenssy/p/3317866.html
02.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末著拭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子牍帚,更是在濱河造成了極大的恐慌儡遮,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件暗赶,死亡現(xiàn)場(chǎng)離奇詭異鄙币,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)蹂随,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門十嘿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人糙及,你說(shuō)我怎么就攤上這事详幽。” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵唇聘,是天一觀的道長(zhǎng)版姑。 經(jīng)常有香客問(wèn)我,道長(zhǎng)迟郎,這世上最難降的妖魔是什么剥险? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮宪肖,結(jié)果婚禮上表制,老公的妹妹穿的比我還像新娘。我一直安慰自己控乾,他們只是感情好么介,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蜕衡,像睡著了一般壤短。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上慨仿,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天久脯,我揣著相機(jī)與錄音,去河邊找鬼镰吆。 笑死帘撰,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的万皿。 我是一名探鬼主播摧找,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼相寇!你這毒婦竟也來(lái)了慰于?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤唤衫,失蹤者是張志新(化名)和其女友劉穎婆赠,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體佳励,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡休里,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了赃承。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片妙黍。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖瞧剖,靈堂內(nèi)的尸體忽然破棺而出拭嫁,到底是詐尸還是另有隱情可免,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布做粤,位于F島的核電站浇借,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏怕品。R本人自食惡果不足惜妇垢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望肉康。 院中可真熱鬧闯估,春花似錦、人聲如沸吼和。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)纹安。三九已至尤辱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間厢岂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工阳距, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留塔粒,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓筐摘,卻偏偏與公主長(zhǎng)得像卒茬,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子咖熟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345