1. 程式人生 > 其它 >C#設計模式學習筆記:(7)橋接模式

C#設計模式學習筆記:(7)橋接模式

技術標籤:C#教程c#

本筆記摘抄自:https://www.cnblogs.com/PatrickLiu/p/7699301.html,記錄一下學習過程以備後續查用。

一、引言

今天我們要講結構型設計模式的第二個模式–橋接模式,也有叫橋模式的。橋在我們現實生活中經常是連線著A地和B地,再往後來發展,橋引申為一種紐

帶,比如,絲綢之路是連線亞洲和歐洲的橋樑。有了橋,我們出行更方便了,不需要繞路或搭船。針對橋的使用環境來說,橋解決了跨越和銜接的問題。在

設計模式中的橋接模式也有類似的概念,是連線了兩個不同維度的東西,而且這兩個維度又有強烈的變化。

二、橋接模式介紹

橋接模式:英文名稱–Bridge Pattern;分類–結構型。

2.1、動機(Motivate)

一般遊戲場景中,裝備都會有自己固有的邏輯。比如槍支,有型號,同時又支援在不同的介質平臺上使用,這樣就使得遊戲的裝備具有了兩個變化的維度。

一個變化的維度為“平臺的變化”,另一個變化的維度為“型號的變化”。如果我們要寫程式碼實現這款遊戲,難道我們針對每種平臺都實現一套獨立的裝備嗎?復

用在哪裡?如何應對這種“多維度的變化”?如何利用面向物件技術來使得裝備可以輕鬆地沿著“平臺”和“型號”兩個方向變化,而不引入額外的複雜度?

2.2、意圖(Intent)

將抽象部分與實現部分分離,使它們都可以獨立地變化。–《設計模式》Gof

橋接模式不能只是認為是抽象和實現的分離,它其實並不僅限於此。其實兩個都是抽象的部分,更確切的理解,應該是將一個事物中多個維度的變化分離。

2.3、結構圖(Structure)

在這裡插入圖片描述

2.4、模式的組成
橋接模式的結構包括Abstraction、RefinedAbstraction、Implementor、ConcreteImplementorA和ConcreteImplementorB五個部分,其中:

1)抽象化角色(Abstraction):抽象化給出定義,並儲存一個對實現化物件(Implementor)的引用。

2)修正抽象化角色(Refined Abstraction):擴充套件抽象化角色,改變和修正父類對抽象化的定義。

3)實現化角色(Implementor):這個角色給出實現化角色的介面,但不給出具體的實現。必須指出的是,這個介面不一定與抽象化角色的介面定義相同。

實際上,這兩個介面可以非常不一樣。實現化角色應當只給出底層操作,而抽象化角色應當只給出基於底層操作的更高一層的操作。

4)具體實現化角色(Concrete Implementor):這個角色給出實現化角色介面的具體實現。

在橋接模式中,兩個類Abstraction和Implementor分別定義了抽象與行為型別的介面,通過呼叫兩介面的子類實現抽象與行為的動態組合。

2.5、橋接模式的具體實現

今天我們就以資料庫為例來寫該模式的實現。每種資料庫都有自己的版本,但是每種資料庫在不同的平臺上實現又是不一樣的。比如,微軟的SqlServer數

據庫有2000、2005、2008、2012、2014、2016、2017版本,後面還會有更新的版本,並且這些版本都是執行在Windows作業系統下的。如果要提供Lunix

作業系統下的SqlServer怎麼辦呢?如果又要提供IOS作業系統下的SqlServer資料庫該怎麼辦呢?這個情況就可以使用橋接模式,也就是Brige模式。

下面看看具體的實現:

  class Program
    {
        /// <summary>
        /// 該抽象類就是抽象介面的定義,該型別就相當於是Abstraction型別。
        /// </summary>
        public abstract class Database
        {
            //通過組合方式引用平臺介面,此處就是橋樑,該型別相當於Implementor型別。
            protected PlatformImplementor platformImplementor;

            //通過構造器注入,初始化平臺實現。
            protected Database(PlatformImplementor implementor)
            {
                platformImplementor = implementor;
            }

            //建立資料庫,該操作相當於Abstraction型別的Operation方法。
            public abstract void Create();
        }

        /// <summary>
        /// 該抽象類就是實現介面的定義,該型別就相當於是Implementor型別。
        /// </summary>
        public abstract class PlatformImplementor
        {
            //該方法就相當於Implementor型別的OperationImp方法
            public abstract void Process();
        }

        /// <summary>
        /// SqlServer2000版本的資料庫,相當於RefinedAbstraction型別。
        /// </summary>
        public class SqlServer2000 : Database
        {
            //建構函式初始化
            public SqlServer2000(PlatformImplementor implementor) : base(implementor) { }

            public override void Create()
            {
                platformImplementor.Process();
            }
        }

        /// <summary>
        /// SqlServer2005版本的資料庫,相當於RefinedAbstraction型別。
        /// </summary>
        public class SqlServer2005 : Database
        {
            //建構函式初始化
            public SqlServer2005(PlatformImplementor implementor) : base(implementor) { }

            public override void Create()
            {
                platformImplementor.Process();
            }
        }

        /// <summary>
        /// SqlServer2000版本的資料庫針對Unix作業系統的具體實現,相當於ConcreteImplementorA型別。
        /// </summary>
        public class SqlServer2000UnixImplementor : PlatformImplementor
        {
            public override void Process()
            {
                Console.WriteLine("SqlServer2000針對Unix作業系統的具體實現。");
            }
        }

        /// <summary>
        /// SqlServer2005版本的資料庫針對Unix作業系統的具體實現,相當於ConcreteImplementorB型別。
        /// </summary>
        public sealed class SqlServer2005UnixImplementor : PlatformImplementor
        {
            public override void Process()
            {
                Console.WriteLine("SqlServer2005針對Unix作業系統的具體實現。");
            }
        }

        static void Main(string[] args)
        {
            #region 橋接模式
            //針對不同平臺進行擴充套件,也就是子類化,這個是獨立變化的。
            PlatformImplementor SqlServer2000UnixImp = new SqlServer2000UnixImplementor();

            //資料庫版本也可以進行擴充套件和升級,也進行獨立的變化。
            Database SqlServer2000Unix = new SqlServer2000(SqlServer2000UnixImp);

            //以上就是兩個維度的變化。

            //現在就可以針對Unix作業系統進行操作了。
            SqlServer2000Unix.Create();

            Console.Read();
            #endregion
        }
    }

執行結果如下:

在這裡插入圖片描述
三、橋接模式的實現要點

1)Bridge模式使用“物件間的組合關係”解耦了抽象和實現之間固有的繫結關係,使得抽象和實現可以沿著各自的維度來變化。
2)所謂抽象和實現沿著各自維度的變化,即“子類化”它們,得到各個子類之後,便可以任意組合它們,從而獲得不同平臺上的不同型號。
3)Bridge模式有時候類似於多繼承方案,但是多繼承方案往往違背了類的單一職責原則(即一個類只有一個變化的原因),複用性比較差。Bridge模式對
比於多繼承方案是更好的解決方法。
4)Bridge模式的應用一般在“兩個非常強的變化維度”。有時候即使有兩個變化的維度,但是某個方向的變化維度並不劇烈,換言之兩個變化不會導致縱橫
交錯的結果,並不一定要使用Bridge模式。
3.1、橋接模式的優點
1)把抽象介面與其實現解耦。
2)抽象和實現可以獨立擴充套件,不會影響到對方。
3)實現細節對客戶透明,對使用隱藏了具體的實現細節。
3.2、橋接模式的缺點
1)增加了系統的複雜度
3.3、橋接模式的使用場景
1)一個系統需要在構件的抽象化角色和具體化角色之間新增更多的靈活性,避免在兩個層次之間建立靜態的聯絡。
2)設計要求實現化角色的任何改變不應當影響客戶端,或者實現化角色的改變對客戶端是完全透明的。
3)需要跨越多個平臺的圖形和視窗系統上。
4)一個類存在兩個獨立變化的維度,且兩個維度都需要進行擴充套件。
四、.NET中橋接模式的實現
學習中……,如果誰有好的程式碼分享,可以貼出來。
五、總結
橋接模式是連線客戶端程式碼和具體實現程式碼的一座橋樑,同時它也隔離了實現程式碼的改變對客戶程式碼的影響。在意圖中所說的抽象和實現,這兩個部分其
實都是高度抽象的,前面“抽象”是python基礎教程
指定義了針對客戶端的介面,客戶端其實使用的是Abstract型別或者是RefinedAbstract型別,這兩個型別只是介面,具體的實現委託給了Implementor型別了。Abstract型別子類化的擴充套件也演變成Implementor子類化的變化。依c#教程個人理解,Abstract型別和其子型別在客戶端程式碼和真正實現的程式碼之間起到了橋樑的作用,隔離了Implementor實現程式碼的變化,讓客戶端更穩定,所以意圖才說是講抽象部分和它的實現部分隔離。