深入理解Java設計模式之橋接模式

一、什麼是橋接模式

橋接模式(Bridge Pattern):將抽象部分與它的實現部分分離,使它們都可以獨立地變化。它是一種對象結構型模式,又稱為柄體(Handle and Body)模式或接口(Interface)模式。

二、橋接模式的結構

在橋接模式結構圖中包含如下幾個角色:

  • Abstraction(抽象類):用於定義抽象類的接口,它一般是抽象類而不是接口,其中定義瞭一個Implementor(實現類接口)類型的對象並可以維護該對象,它與Implementor之間具有關聯關系,它既可以包含抽象業務方法,也可以包含具體業務方法。
  • RefinedAbstraction(擴充抽象類):擴充由Abstraction定義的接口,通常情況下它不再是抽象類而是具體類,它實現瞭在Abstraction中聲明的抽象業務方法,在RefinedAbstraction中可以調用在Implementor中定義的業務方法。
  • Implementor(實現類接口):定義實現類的接口,這個接口不一定要與Abstraction的接口完全一致,事實上這兩個接口可以完全不同,一般而言,Implementor接口僅提供基本操作,而Abstraction定義的接口可能會做更多更復雜的操作。Implementor接口對這些基本操作進行瞭聲明,而具體實現交給其子類。通過關聯關系,在Abstraction中不僅擁有自己的方法,還可以調用到Implementor中定義的方法,使用關聯關系來替代繼承關系。
  • ConcreteImplementor(具體實現類):具體實現Implementor接口,在不同的ConcreteImplementor中提供基本操作的不同實現,在程序運行時,ConcreteImplementor對象將替換其父類對象,提供給抽象類具體的業務操作方法。

三、橋接模式的使用場景

  • 當對象存在多種變化的因素時,考慮對其變化的因素和場景進行抽象,然後進行橋接;如筆擁有不同的功能。
  • 當多個對象存在多種變化的因素時,考慮將這部分變化的部分抽象出來再聚合進來;比如不同品牌的電腦安裝不同的系統、使用不同的軟件等,相當於將第一條進行橫向擴展,增加橋接的數量。

四、橋接模式的優缺點

優點:

(1)分離抽象接口及其實現部分。橋接模式使用“對象間的關聯關系”解耦瞭抽象和實現之間固有的綁定關系,使得抽象和實現可以沿著各自的維度來變化。所謂抽象和實現沿著各自維度的變化,也就是說抽象和實現不再在同一個繼承層次結構中,而是“子類化”它們,使它們各自都具有自己的子類,以便任何組合子類,從而獲得多維度組合對象。

(2)在很多情況下,橋接模式可以取代多層繼承方案,多層繼承方案違背瞭“單一職責原則”,復用性較差,且類的個數非常多,橋接模式是比多層繼承方案更好的解決方法,它極大減少瞭子類的個數。

(3)橋接模式提高瞭系統的可擴展性,在兩個變化維度中任意擴展一個維度,都不需要修改原有系統,符合“開閉原則”。

缺點:

(1)橋接模式的使用會增加系統的理解與設計難度,由於關聯關系建立在抽象層,要求開發者一開始就針對抽象層進行設計與編程。

(2)橋接模式要求正確識別出系統中兩個獨立變化的維度,因此其使用范圍具有一定的局限性,如何正確識別兩個獨立維度也需要一定的經驗積累。

五、裝飾,橋接和適配器模式的異同

三者都是結構型的設計模式,而且都存在依賴抽象的情況

適配器模式:

重點強調的是適配的功能。(適配器依賴抽象)

關鍵點是:

主體類和適配器類實現相同的接口A

  • 主體類依賴適配器類
  • 適配器類依賴抽象接口B
  • 被適配的類實現抽象接口B

最終的效果就是,主體類可以使用之前不相關的被適配類中的某些功能。

橋接模式:

重點強調的是多維度的變化。(主體類直接依賴抽象)

關鍵點是:

  • 主體類依賴抽象A
  • 主體類具有多個不同的實現類
  • 抽象A具有多個不同的實現類

最終的效果就是,主體類的實現類和抽象的實現類分別可以在兩個維度上進行各自的變化。如果主體類依賴多個抽象,則維度進行增加,方便擴展。

裝飾器模式:

重點強調的是裝飾功能。(主體類不僅依賴抽象,而且實現該抽象接口)

關鍵點是

  • 抽象A具有多個具體子類
  • 裝飾器類依賴抽象A
  • 裝飾器類實現抽象A
  • 裝飾器類存在不同子類

最終的效果就是,(裝飾器實現類)對(原抽象的子類)進行某些方法的功能加強。

六、橋接模式的實現

首先抽象出電視機,提供遙控器改變的行為方法。

/// <summary>
    /// 電視機,提供抽象方法
    /// </summary>
    public abstract class TV
    {
        public abstract void On();
        public abstract void Off();
        public abstract void tuneChannel();
    }

創建具體的電視機,繼承自抽象電視機類:

/// <summary>
    /// 三星牌電視機,重寫基類的抽象方法
    /// </summary>
    public class Samsung:TV
    {
        public override void On()
        {
            Console.WriteLine("三星牌電視機已經打開瞭");
        }
         public override void Off()
        {
            Console.WriteLine("三星牌電視機已經關掉瞭");
        }
         public override void tuneChannel()
        {
            Console.WriteLine("三星牌電視機換頻道");
        }
    }
     /// <summary>
    /// 長虹牌電視機,重寫基類的抽象方法
    /// 提供具體的實現
    /// </summary>
    public class ChangHong : TV
    {
        public override void On()
        {
            Console.WriteLine("長虹牌電視機已經打開瞭");
        }
         public override void Off()
        {
            Console.WriteLine("長虹牌電視機已經關掉瞭");
        }
         public override void tuneChannel()
        {
            Console.WriteLine("長虹牌電視機換頻道");
        }
    }

然後抽象出概覽中的遙控器,扮演抽象話的角色

/// <summary>
    ///  抽象概念中的遙控器,扮演抽象化角色
    /// </summary>
    public abstract class RemoteControl
    {
        public TV implementor { get; set; }
         /// <summary>
        /// 開電視機
        /// 這裡抽象類中不再提供實現瞭,而是調用實現類中的實現
        /// </summary>
        public virtual void On()
        {
            implementor.On();
        }
         /// <summary>
        /// 關電視機
        /// </summary>
        public virtual void Off()
        {
            implementor.Off();
        }
         /// <summary>
        /// 換頻道
        /// </summary>
        public virtual void SetChannel()
        {
            implementor.tuneChannel();
        }
    }

創建具體遙控器類:這裡面,我重寫瞭更換頻道的方法,其實還可以重寫其他的方法

/// <summary>
    /// 具體遙控器類
    /// </summary>
    public class ConcreteRemote:RemoteControl
    {
        /// <summary>
        /// 重寫更換頻道方法
        /// </summary>
        public override void SetChannel()
        {
            Console.WriteLine("重寫更換頻道方法");
            base.SetChannel();
        }
    }

客戶端代碼:

static void Main(string[] args)
        {
            // 創建一個遙控器
            RemoteControl remoteControl = new ConcreteRemote();
             //長虹電視機
            remoteControl.implementor = new ChangHong();
            remoteControl.On();
            remoteControl.SetChannel();
            remoteControl.Off();
            Console.WriteLine();
             // 三星牌電視機
            remoteControl.implementor = new Samsung();
            remoteControl.On();
            remoteControl.SetChannel();
            remoteControl.Off();
            Console.Read();
        }

這樣接實現瞭橋接模式的設計,遙控器的功能實現方法不是在遙控器中去實現瞭,而是將實現部分用來另一個電視機類去封裝它,遙控器中隻包含電視機類的一個引用,通過橋接模式,我們把抽象化和實現化部分分離開瞭,這樣可以很好應對這兩方面的變化。

七、總結

橋接模式是一個非常有用的模式,在橋接模式中體現瞭很多面向對象設計原則的思想,包括“單一職責原則”、“開閉原則”、“合成復用原則”、“裡氏代換原則”、“依賴倒轉原則”等。熟悉橋接模式有助於我們深入理解這些設計原則,也有助於我們形成正確的設計思想和培養良好的設計風格。

本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!

推薦閱讀: