深入理解Java設(shè)計(jì)模式之橋接模式
一、什么是橋接模式
橋接模式(Bridge Pattern
):將抽象部分與它的實(shí)現(xiàn)部分分離,使它們都可以獨(dú)立地變化。它是一種對(duì)象結(jié)構(gòu)型模式,又稱(chēng)為柄體(Handle and Body
)模式或接口(Interface
)模式。
二、橋接模式的結(jié)構(gòu)
在橋接模式結(jié)構(gòu)圖中包含如下幾個(gè)角色:
Abstraction
(抽象類(lèi)):用于定義抽象類(lèi)的接口,它一般是抽象類(lèi)而不是接口,其中定義了一個(gè)Implementor(實(shí)現(xiàn)類(lèi)接口)類(lèi)型的對(duì)象并可以維護(hù)該對(duì)象,它與Implementor之間具有關(guān)聯(lián)關(guān)系,它既可以包含抽象業(yè)務(wù)方法,也可以包含具體業(yè)務(wù)方法。RefinedAbstraction
(擴(kuò)充抽象類(lèi)):擴(kuò)充由Abstraction定義的接口,通常情況下它不再是抽象類(lèi)而是具體類(lèi),它實(shí)現(xiàn)了在A(yíng)bstraction中聲明的抽象業(yè)務(wù)方法,在RefinedAbstraction中可以調(diào)用在Implementor中定義的業(yè)務(wù)方法。Implementor
(實(shí)現(xiàn)類(lèi)接口):定義實(shí)現(xiàn)類(lèi)的接口,這個(gè)接口不一定要與Abstraction的接口完全一致,事實(shí)上這兩個(gè)接口可以完全不同,一般而言,Implementor接口僅提供基本操作,而Abstraction定義的接口可能會(huì)做更多更復(fù)雜的操作。Implementor接口對(duì)這些基本操作進(jìn)行了聲明,而具體實(shí)現(xiàn)交給其子類(lèi)。通過(guò)關(guān)聯(lián)關(guān)系,在A(yíng)bstraction中不僅擁有自己的方法,還可以調(diào)用到Implementor中定義的方法,使用關(guān)聯(lián)關(guān)系來(lái)替代繼承關(guān)系。ConcreteImplementor
(具體實(shí)現(xiàn)類(lèi)):具體實(shí)現(xiàn)Implementor接口,在不同的ConcreteImplementor中提供基本操作的不同實(shí)現(xiàn),在程序運(yùn)行時(shí),ConcreteImplementor對(duì)象將替換其父類(lèi)對(duì)象,提供給抽象類(lèi)具體的業(yè)務(wù)操作方法。
三、橋接模式的使用場(chǎng)景
- 當(dāng)對(duì)象存在多種變化的因素時(shí),考慮對(duì)其變化的因素和場(chǎng)景進(jìn)行抽象,然后進(jìn)行橋接;如筆擁有不同的功能。
- 當(dāng)多個(gè)對(duì)象存在多種變化的因素時(shí),考慮將這部分變化的部分抽象出來(lái)再聚合進(jìn)來(lái);比如不同品牌的電腦安裝不同的系統(tǒng)、使用不同的軟件等,相當(dāng)于將第一條進(jìn)行橫向擴(kuò)展,增加橋接的數(shù)量。
四、橋接模式的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
(1)分離抽象接口及其實(shí)現(xiàn)部分。橋接模式使用“對(duì)象間的關(guān)聯(lián)關(guān)系”解耦了抽象和實(shí)現(xiàn)之間固有的綁定關(guān)系,使得抽象和實(shí)現(xiàn)可以沿著各自的維度來(lái)變化。所謂抽象和實(shí)現(xiàn)沿著各自維度的變化,也就是說(shuō)抽象和實(shí)現(xiàn)不再在同一個(gè)繼承層次結(jié)構(gòu)中,而是“子類(lèi)化”它們,使它們各自都具有自己的子類(lèi),以便任何組合子類(lèi),從而獲得多維度組合對(duì)象。
(2)在很多情況下,橋接模式可以取代多層繼承方案,多層繼承方案違背了“單一職責(zé)原則”,復(fù)用性較差,且類(lèi)的個(gè)數(shù)非常多,橋接模式是比多層繼承方案更好的解決方法,它極大減少了子類(lèi)的個(gè)數(shù)。
(3)橋接模式提高了系統(tǒng)的可擴(kuò)展性,在兩個(gè)變化維度中任意擴(kuò)展一個(gè)維度,都不需要修改原有系統(tǒng),符合“開(kāi)閉原則”。
缺點(diǎn):
(1)橋接模式的使用會(huì)增加系統(tǒng)的理解與設(shè)計(jì)難度,由于關(guān)聯(lián)關(guān)系建立在抽象層,要求開(kāi)發(fā)者一開(kāi)始就針對(duì)抽象層進(jìn)行設(shè)計(jì)與編程。
(2)橋接模式要求正確識(shí)別出系統(tǒng)中兩個(gè)獨(dú)立變化的維度,因此其使用范圍具有一定的局限性,如何正確識(shí)別兩個(gè)獨(dú)立維度也需要一定的經(jīng)驗(yàn)積累。
五、裝飾,橋接和適配器模式的異同
三者都是結(jié)構(gòu)型的設(shè)計(jì)模式,而且都存在依賴(lài)抽象的情況
適配器模式:
重點(diǎn)強(qiáng)調(diào)的是適配的功能。(適配器依賴(lài)抽象)
關(guān)鍵點(diǎn)是:
主體類(lèi)和適配器類(lèi)實(shí)現(xiàn)相同的接口A(yíng)
- 主體類(lèi)依賴(lài)適配器類(lèi)
- 適配器類(lèi)依賴(lài)抽象接口B
- 被適配的類(lèi)實(shí)現(xiàn)抽象接口B
最終的效果就是,主體類(lèi)可以使用之前不相關(guān)的被適配類(lèi)中的某些功能。
橋接模式:
重點(diǎn)強(qiáng)調(diào)的是多維度的變化。(主體類(lèi)直接依賴(lài)抽象)
關(guān)鍵點(diǎn)是:
- 主體類(lèi)依賴(lài)抽象A
- 主體類(lèi)具有多個(gè)不同的實(shí)現(xiàn)類(lèi)
- 抽象A具有多個(gè)不同的實(shí)現(xiàn)類(lèi)
最終的效果就是,主體類(lèi)的實(shí)現(xiàn)類(lèi)和抽象的實(shí)現(xiàn)類(lèi)分別可以在兩個(gè)維度上進(jìn)行各自的變化。如果主體類(lèi)依賴(lài)多個(gè)抽象,則維度進(jìn)行增加,方便擴(kuò)展。
裝飾器模式:
重點(diǎn)強(qiáng)調(diào)的是裝飾功能。(主體類(lèi)不僅依賴(lài)抽象,而且實(shí)現(xiàn)該抽象接口)
關(guān)鍵點(diǎn)是:
- 抽象A具有多個(gè)具體子類(lèi)
- 裝飾器類(lèi)依賴(lài)抽象A
- 裝飾器類(lèi)實(shí)現(xiàn)抽象A
- 裝飾器類(lèi)存在不同子類(lèi)
最終的效果就是,(裝飾器實(shí)現(xiàn)類(lèi))對(duì)(原抽象的子類(lèi))進(jìn)行某些方法的功能加強(qiáng)。
六、橋接模式的實(shí)現(xiàn)
首先抽象出電視機(jī),提供遙控器改變的行為方法。
/// <summary> /// 電視機(jī),提供抽象方法 /// </summary> public abstract class TV { public abstract void On(); public abstract void Off(); public abstract void tuneChannel(); }
創(chuàng)建具體的電視機(jī),繼承自抽象電視機(jī)類(lèi):
/// <summary> /// 三星牌電視機(jī),重寫(xiě)基類(lèi)的抽象方法 /// </summary> public class Samsung:TV { public override void On() { Console.WriteLine("三星牌電視機(jī)已經(jīng)打開(kāi)了"); } public override void Off() { Console.WriteLine("三星牌電視機(jī)已經(jīng)關(guān)掉了"); } public override void tuneChannel() { Console.WriteLine("三星牌電視機(jī)換頻道"); } } /// <summary> /// 長(zhǎng)虹牌電視機(jī),重寫(xiě)基類(lèi)的抽象方法 /// 提供具體的實(shí)現(xiàn) /// </summary> public class ChangHong : TV { public override void On() { Console.WriteLine("長(zhǎng)虹牌電視機(jī)已經(jīng)打開(kāi)了"); } public override void Off() { Console.WriteLine("長(zhǎng)虹牌電視機(jī)已經(jīng)關(guān)掉了"); } public override void tuneChannel() { Console.WriteLine("長(zhǎng)虹牌電視機(jī)換頻道"); } }
然后抽象出概覽中的遙控器,扮演抽象話(huà)的角色
/// <summary> /// 抽象概念中的遙控器,扮演抽象化角色 /// </summary> public abstract class RemoteControl { public TV implementor { get; set; } /// <summary> /// 開(kāi)電視機(jī) /// 這里抽象類(lèi)中不再提供實(shí)現(xiàn)了,而是調(diào)用實(shí)現(xiàn)類(lèi)中的實(shí)現(xiàn) /// </summary> public virtual void On() { implementor.On(); } /// <summary> /// 關(guān)電視機(jī) /// </summary> public virtual void Off() { implementor.Off(); } /// <summary> /// 換頻道 /// </summary> public virtual void SetChannel() { implementor.tuneChannel(); } }
創(chuàng)建具體遙控器類(lèi):這里面,我重寫(xiě)了更換頻道的方法,其實(shí)還可以重寫(xiě)其他的方法
/// <summary> /// 具體遙控器類(lèi) /// </summary> public class ConcreteRemote:RemoteControl { /// <summary> /// 重寫(xiě)更換頻道方法 /// </summary> public override void SetChannel() { Console.WriteLine("重寫(xiě)更換頻道方法"); base.SetChannel(); } }
客戶(hù)端代碼:
static void Main(string[] args) { // 創(chuàng)建一個(gè)遙控器 RemoteControl remoteControl = new ConcreteRemote(); //長(zhǎng)虹電視機(jī) remoteControl.implementor = new ChangHong(); remoteControl.On(); remoteControl.SetChannel(); remoteControl.Off(); Console.WriteLine(); // 三星牌電視機(jī) remoteControl.implementor = new Samsung(); remoteControl.On(); remoteControl.SetChannel(); remoteControl.Off(); Console.Read(); }
這樣接實(shí)現(xiàn)了橋接模式的設(shè)計(jì),遙控器的功能實(shí)現(xiàn)方法不是在遙控器中去實(shí)現(xiàn)了,而是將實(shí)現(xiàn)部分用來(lái)另一個(gè)電視機(jī)類(lèi)去封裝它,遙控器中只包含電視機(jī)類(lèi)的一個(gè)引用,通過(guò)橋接模式,我們把抽象化和實(shí)現(xiàn)化部分分離開(kāi)了,這樣可以很好應(yīng)對(duì)這兩方面的變化。
七、總結(jié)
橋接模式是一個(gè)非常有用的模式,在橋接模式中體現(xiàn)了很多面向?qū)ο笤O(shè)計(jì)原則的思想,包括“單一職責(zé)原則”、“開(kāi)閉原則”、“合成復(fù)用原則”、“里氏代換原則”、“依賴(lài)倒轉(zhuǎn)原則”等。熟悉橋接模式有助于我們深入理解這些設(shè)計(jì)原則,也有助于我們形成正確的設(shè)計(jì)思想和培養(yǎng)良好的設(shè)計(jì)風(fēng)格。
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Java讀寫(xiě)txt文件時(shí)防止中文亂碼問(wèn)題出現(xiàn)的方法介紹
這篇文章主要介紹了Java讀寫(xiě)txt文件時(shí)防止中文亂碼問(wèn)題出現(xiàn)的方法,同時(shí)需要注意系統(tǒng)默認(rèn)的文本保存編碼的設(shè)置,需要的朋友可以參考下2015-12-12Jenkins Host key verification failed問(wèn)題解決
這篇文章主要介紹了Jenkins Host key verification failed問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11springboot中使用過(guò)濾器,jsoup過(guò)濾XSS腳本詳解
這篇文章主要介紹了springboot中使用過(guò)濾器,jsoup過(guò)濾XSS腳本詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12Spring Cloud 2023 新特性支持同步網(wǎng)關(guān)
這篇文章主要為大家介紹了Spring Cloud 2023 新特性支持同步網(wǎng)關(guān)講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10Java實(shí)現(xiàn)給圖片添加圖片水印,文字水印及馬賽克的方法示例
這篇文章主要介紹了Java實(shí)現(xiàn)給圖片添加圖片水印,文字水印及馬賽克的方法,涉及java針對(duì)圖片的讀取、水印添加、馬賽克設(shè)置等相關(guān)操作技巧,需要的朋友可以參考下2018-01-01Java中文件創(chuàng)建于寫(xiě)入內(nèi)容的常見(jiàn)方法
在日常開(kāi)發(fā)中,肯定離不開(kāi)要和文件打交道,今天就簡(jiǎn)單羅列一下平時(shí)比較常用的創(chuàng)建文件并向文件中寫(xiě)入數(shù)據(jù)的幾種方式,希望對(duì)大家有一定的幫助2023-10-10