秒懂設計模式之橋接模式(Bridge Pattern)

前言

人在IT江湖飄,不懂設計模式咋裝X?

橋接模式在日常開發(fā)中不是特別常用,主要是因為上手難度較大签则,但是對于理解面向?qū)ο笤O計有非常大的幫助。

定義

橋接模式是將抽象部分與它的實現(xiàn)部分分離铐料,使它們都可以獨立地變化渐裂。它是一種對象結(jié)構(gòu)型模式,又稱為柄體(Handle and Body)模式或接口(Interfce)模式钠惩。

使用場景

我們大家都熟悉柒凉,顧名思義就是用來將河的兩岸聯(lián)系起來的。而此處的橋是用來將兩個獨立的結(jié)構(gòu)聯(lián)系起來篓跛,而這兩個被聯(lián)系起來的結(jié)構(gòu)可以獨立的變化膝捞,所有其他的理解只要建立在這個層面上就會比較容易。

下面是一些官方的說明愧沟,比較晦澀蔬咬,必須等你有一定的經(jīng)驗后才能理解: 1. 如果一個系統(tǒng)需要在抽象化和具體化之間增加更多的靈活性,避免在兩個層次之間建立靜態(tài)的繼承關系沐寺,通過橋接模式可以使它們在抽象層建立一個關聯(lián)關系林艘。

  1. “抽象部分”和“實現(xiàn)部分”可以以繼承的方式獨立擴展而互不影響,在程序運行時可以動態(tài)將一個抽象化子類的對象和一個實現(xiàn)化子類的對象進行組合混坞,即系統(tǒng)需要對抽象化角色和實現(xiàn)化角色進行動態(tài)耦合狐援。

  2. 一個類存在兩個(或多個)獨立變化的維度,且這兩個(或多個)維度都需要獨立進行擴展究孕。

  3. 對于那些不希望使用繼承或因為多層繼承導致系統(tǒng)類的個數(shù)急劇增加的系統(tǒng)啥酱,橋接模式尤為適用。

如何實現(xiàn)

業(yè)務場景

在講策略模式的時候蚊俺,王二狗和牛翠花不是要到天津之眼去約炮懈涛,不,約會嘛泳猬,兩人到那后先去星巴克喝咖啡了,星巴克提供了多種選擇宇植,從容量上說有大杯得封,中杯,小杯指郁,從口味上說有原味忙上,加糖,這可難為了有選擇恐懼癥的牛翠花闲坎,半天點不出來疫粥,后面的人都開始罵娘了茬斧,王二狗也只能陪著笑臉道歉。 其實被難為的除了牛翠花梗逮,還有給星巴克做訂單系統(tǒng)的外包公司的程序員林蛋大项秉。一開始提需求的時候星巴克說我們只有正常杯(中杯),原味和加糖這幾種選擇慷彤,人家林蛋大也是有兩年工作經(jīng)驗的碼農(nóng)娄蔼,這需求不在話下,蛋大還想到了要面對抽象編程底哗。

首先定義一個點咖啡接口岁诉,里面有一個下單方法,至于點哪種口味的咖啡跋选,就由其子類去決定涕癣,完美,蛋大好牛逼扒氨辍属划!

public interface ICoffee {
    void orderCoffee(int count);
}

原味咖啡類

public class CoffeeOriginal implements ICoffee {
    @Override
    public void orderCoffee(int count) {
        System.out.println(String.format("原味咖啡%d杯",count));
    }
}

加糖咖啡類

public class CoffeeWithSugar implements ICoffee {
    @Override
    public void orderCoffee(int count) {
        System.out.println(String.format("加糖咖啡%d杯",count));
    }
}

搞定收工,王者榮耀搞起候生!項目經(jīng)理突然過來了:蛋大啊同眯,客戶那邊說了,他們準備加兩個容量規(guī)格的咖啡唯鸭,大杯和小杯须蜗,你改一下。林蛋大:what目溉?尼瑪為什么不早說明肮,老子剛寫完。胸中雖有萬千牢騷缭付,還不得平復一下心情去改代碼柿估,何必呢?蛋大心中暗喜陷猫,幸好老子是面向抽象編程的秫舌,對應加幾個實現(xiàn)類不就得了?

//中杯加糖
public class CoffeeWithSugar implements ICoffee {
    @Override
    public void orderCoffee(int count) {
        System.out.println(String.format("中杯加糖咖啡%d杯",count));
    }
}
//大杯加糖
public class LargeCoffeeWithSugar implements ICoffee {
    @Override
    public void orderCoffee(int count) {
        System.out.println(String.format("大杯加糖咖啡%d杯",count));
    }
}
绣檬。足陨。。

加著加著蛋大慌了娇未,共需要3x2=6個類啊墨缘,大杯原味和加糖,中杯原味和加糖,小杯原味和加糖镊讼。過段時間萬一那二筆客戶又要出加奶宽涌,加蜂蜜等等口味,說不定還有迷你杯蝶棋,女神杯等等規(guī)格的咖啡卸亮,那我這邊的類不就爆炸了嗎?看來的去找個設計模式了嚼松。嫡良。。

此場景橋接模式正合適献酗,這里有兩個變化維度寝受,咖啡的容量和口味,而且都需要獨立變化罕偎。如果使用繼承的方式很澄,隨著變化類就會急劇的增加。你可以將容量理解為抽象部分颜及,而口味理解為實現(xiàn)部分甩苛,這兩個部分需要橋接。

使用橋接模式

橋接模式UML 圖如下

image.jpg

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

  • 抽象化(Abstraction)角色:抽象化給出的定義俏站,并保存一個對實現(xiàn)化對象的引用讯蒲。
  • 修正抽象化(RefinedAbstraction)角色:擴展抽象化角色,改變和修正父類對抽象化的定義肄扎。
  • 實現(xiàn)化(Implementor)角色:這個角色給出實現(xiàn)化角色的接口墨林,但不給出具體的實現(xiàn)。必須指出的是犯祠,這個接口不一定和抽象化角色的接口定義相同旭等,實際上,這兩個接口可以非常不一樣衡载。實現(xiàn)化角色應當只給出底層操作搔耕,而抽象化角色應當只給出基于底層操作的更高一層的操作。
  • 具體實現(xiàn)化(ConcreteImplementor)角色:這個角色給出實現(xiàn)化角色接口的具體實現(xiàn)痰娱。

抽象化角色就像是一個水杯的手柄弃榨,而實現(xiàn)化角色和具體實現(xiàn)化角色就像是水杯的杯身。手柄控制杯身猜揪,這就是此模式別名“柄體”的來源惭墓。

林蛋大查了半天不知道使用哪個設計模式,只能求助前輩王二狗了而姐。電話通了:狗哥,我這有個問題划咐。拴念。钧萍。王二狗:我這正解決終身大事呢,沒工夫理你政鼠,你去調(diào)查一下橋接模式风瘦。林蛋大:不愧是大神,改天請你和嫂子吃飯公般,先掛啦万搔。掛電話后,蛋大就開始用橋接模式重構(gòu)代碼了官帘。

蛋大分析了當前業(yè)務場景瞬雹,認為可以將咖啡的容量作為抽象化Abstraction,而咖啡口味為實現(xiàn)化Implementor

第一步:創(chuàng)建抽象化部分:

//抽象化Abstraction
public abstract class Coffee {
    protected ICoffeeAdditives additives;
    public Coffee(ICoffeeAdditives additives){
        this.additives=additives;
    }
    public abstract void orderCoffee(int count);
}

我們可以看到刽虹,Coffee持有了ICoffeeAdditives 引用酗捌,ICoffeeAdditives 的實例是通過構(gòu)造函數(shù)注入的,這個過程就是我們所說的橋接過程涌哲。我們通過這個引用就可以調(diào)用ICoffeeAdditives的方法胖缤,進而將Coffee的行為與ICoffeeAdditives的行為通過orderCoffee()方法而組合起來。

下面是一個對抽象化修正的一個類,里面增加了一個品控的方法

//RefinedAbstraction
public abstract class RefinedCoffee extends Coffee {
    public RefinedCoffee(ICoffeeAdditives additives) {
        super(additives);
    }
    public void checkQuality(){
        Random ran=new Random();
        System.out.println(String.format("%s 添加%s",additives.getClass().getSimpleName(),ran.nextBoolean()?"太多":"正常"));
    }
}

第二步:創(chuàng)建實現(xiàn)化部分

public interface ICoffeeAdditives {
    void addSomething();
}
//加奶
public class Milk implements ICoffeeAdditives {
    @Override
    public void addSomething() {
        System.out.println("加奶");
    }
}
//加糖
public class Sugar implements ICoffeeAdditives {
    @Override
    public void addSomething() {
        System.out.println("加糖");
    }
}

第三步:客戶端調(diào)用

public static void main(String[] args) {
        //點兩杯加奶的大杯咖啡
        RefinedCoffee largeWithMilk=new LargeCoffee(new Milk());
        largeWithMilk.orderCoffee(2);
        largeWithMilk.checkQuality();
    }

輸出結(jié)果:

加奶
大杯咖啡2杯
Milk 添加太多

通過使用橋接模式阀圾,就使得咖啡的容量和口味這兩個維度可以獨立變化哪廓,互不干擾。林蛋大終于完成了代碼的重構(gòu)初烘,回頭一看王者榮耀由于惡意掛機被扣除15個信用分涡真,暫時不能進行排位賽,無奈只能再去鞏固一下橋接模式了账月。

優(yōu)缺點

優(yōu)點:

  • 分離抽象接口及其實現(xiàn)部分综膀。橋接模式使用“對象間的關聯(lián)關系”解耦了抽象和實現(xiàn)之間固有的綁定關系,使得抽象和實現(xiàn)可以沿著各自的維度來變化局齿。所謂抽象和實現(xiàn)沿著各自維度的變化剧劝,也就是說抽象和實現(xiàn)不再在同一個繼承層次結(jié)構(gòu)中,而是“子類化”它們抓歼,使它們各自都具有自己的子類讥此,以便任何組合子類,從而獲得多維度組合對象谣妻。
  • 在很多情況下萄喳,橋接模式可以取代多層繼承方案,多層繼承方案違背了“單一職責原則”蹋半,復用性較差他巨,且類的個數(shù)非常多,橋接模式是比多層繼承方案更好的解決方法,它極大減少了子類的個數(shù)染突。
  • 橋接模式提高了系統(tǒng)的可擴展性捻爷,在兩個變化維度中任意擴展一個維度,都不需要修改原有系統(tǒng)份企,符合“開閉原則”也榄。

缺點:

  • 橋接模式的使用會增加系統(tǒng)的理解與設計難度,由于關聯(lián)關系建立在抽象層司志,要求開發(fā)者一開始就針對抽象層進行設計與編程甜紫。
  • 橋接模式要求正確識別出系統(tǒng)中兩個獨立變化的維度,因此其使用范圍具有一定的局限性骂远,如何正確識別兩個獨立維度也需要一定的經(jīng)驗積累囚霸。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市吧史,隨后出現(xiàn)的幾起案子邮辽,更是在濱河造成了極大的恐慌,老刑警劉巖贸营,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吨述,死亡現(xiàn)場離奇詭異,居然都是意外死亡钞脂,警方通過查閱死者的電腦和手機揣云,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來冰啃,“玉大人邓夕,你說我怎么就攤上這事⊙忠悖” “怎么了焚刚?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長扇调。 經(jīng)常有香客問我矿咕,道長,這世上最難降的妖魔是什么狼钮? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任碳柱,我火速辦了婚禮,結(jié)果婚禮上熬芜,老公的妹妹穿的比我還像新娘莲镣。我一直安慰自己,他們只是感情好涎拉,可當我...
    茶點故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布瑞侮。 她就那樣靜靜地躺著的圆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪区岗。 梳的紋絲不亂的頭發(fā)上略板,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天毁枯,我揣著相機與錄音慈缔,去河邊找鬼。 笑死种玛,一個胖子當著我的面吹牛藐鹤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播赂韵,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼娱节,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了祭示?” 一聲冷哼從身側(cè)響起肄满,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤陵刹,失蹤者是張志新(化名)和其女友劉穎鹃锈,沒想到半個月后缩赛,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體胸竞,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡钞馁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年晃财,在試婚紗的時候發(fā)現(xiàn)自己被綠了隅俘。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片牙瓢。...
    茶點故事閱讀 40,852評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡毡代,死狀恐怖阅羹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情教寂,我是刑警寧澤捏鱼,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站酪耕,受9級特大地震影響导梆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜因妇,卻給世界環(huán)境...
    茶點故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一问潭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧婚被,春花似錦狡忙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽窜觉。三九已至,卻和暖如春北专,著一層夾襖步出監(jiān)牢的瞬間禀挫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工拓颓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留语婴,地道東北人。 一個月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓驶睦,卻偏偏與公主長得像砰左,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子场航,可洞房花燭夜當晚...
    茶點故事閱讀 45,851評論 2 361

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

  • 【學習難度:★★★☆☆缠导,使用頻率:★★★☆☆】直接出處:橋接模式梳理和學習:https://github.com/...
    BruceOuyang閱讀 910評論 0 2
  • 1.初識橋接模式 將抽象部分與它的實現(xiàn)部分分離,使它們都可以獨立地變化溉痢。 Abstraction:抽象部分的接口僻造。...
    王偵閱讀 921評論 0 7
  • 一、應用場景 設想如果要繪制矩形孩饼、圓形髓削、橢圓、正方形捣辆,我們至少需要4個形狀類蔬螟,但是如果繪制的圖形需要具有不同的顏色...
    QuantRuu閱讀 785評論 0 51
  • 原文傳送門 1 介紹 橋接模式是對象的結(jié)構(gòu)模式。又稱為柄體(Handle and Body)模式或接口(Inter...
    dd299閱讀 516評論 0 1
  • 一個懂得感恩的人汽畴,一定有一顆善良的心旧巾,一定會有福報。感恩我的父母把我?guī)У绞郎先绦o予我最寶貴的生命鲁猩,感恩我的奶奶含辛...
    包包_3a0d閱讀 182評論 0 1