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

来源:https://www.cnblogs.com/atomy/archive/2020/01/19/12209509.html

本筆記摘抄自:https://www.cnblogs.com/PatrickLiu/p/7699301.html,記錄一下學習過程以備後續查用。 一、引言 今天我們要講結構型設計模式的第二個模式--橋接模式,也有叫橋模式的。橋在我們現實生活中經常是連接著A地和B地,再往後來發展,橋引申為一種紐 帶, ...


    本筆記摘抄自: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
        }
    }
View Code

    運行結果如下:

    三、橋接模式的實現要點

    1)Bridge模式使用“對象間的組合關係”解耦了抽象和實現之間固有的綁定關係,使得抽象和實現可以沿著各自的維度來變化。

    2)所謂抽象和實現沿著各自維度的變化,即“子類化”它們,得到各個子類之後,便可以任意組合它們,從而獲得不同平臺上的不同型號。

    3)Bridge模式有時候類似於多繼承方案,但是多繼承方案往往違背了類的單一職責原則(即一個類只有一個變化的原因),復用性比較差。Bridge模式對

比於多繼承方案是更好的解決方法。

    4)Bridge模式的應用一般在“兩個非常強的變化維度”。有時候即使有兩個變化的維度,但是某個方向的變化維度並不劇烈,換言之兩個變化不會導致縱橫

交錯的結果,並不一定要使用Bridge模式。

    3.1、橋接模式的優點

    1)把抽象介面與其實現解耦。

    2)抽象和實現可以獨立擴展,不會影響到對方。

    3)實現細節對客戶透明,對使用隱藏了具體的實現細節。

    3.2、橋接模式的缺點

    1)增加了系統的複雜度

    3.3、橋接模式的使用場景

    1)一個系統需要在構件的抽象化角色和具體化角色之間添加更多的靈活性,避免在兩個層次之間建立靜態的聯繫。

    2)設計要求實現化角色的任何改變不應當影響客戶端,或者實現化角色的改變對客戶端是完全透明的。

    3)需要跨越多個平臺的圖形和視窗系統上。

    4)一個類存在兩個獨立變化的維度,且兩個維度都需要進行擴展。

    四、.NET中橋接模式的實現

    學習中……,如果誰有好的代碼分享,可以貼出來。

    五、總結

    橋接模式是連接客戶端代碼和具體實現代碼的一座橋梁,同時它也隔離了實現代碼的改變對客戶代碼的影響。在意圖中所說的抽象和實現,這兩個部分其

實都是高度抽象的,前面“抽象”是指定義了針對客戶端的介面,客戶端其實使用的是Abstract類型或者是RefinedAbstract類型,這兩個類型只是介面,具體的

實現委托給了Implementor類型了。Abstract類型子類化的擴展也演變成Implementor子類化的變化。依個人理解,Abstract類型和其子類型在客戶端代碼和真

正實現的代碼之間起到了橋梁的作用,隔離了Implementor實現代碼的變化,讓客戶端更穩定,所以意圖才說是講抽象部分和它的實現部分隔離。


您的分享是我們最大的動力!

更多相關文章
  •   Spark Streaming對實時數據流進行分析處理,源源不斷的從數據源接收數據切割成一個個時間間隔進行處理;    流處理與批處理有明顯區別,批處理中的數據有明顯的邊界、數據規模已知;而流處理數據流並沒有邊界,也未知數據規模;    ...
  • 函數 函數參數 參數及返回值類型 可選參數 預設參數 剩餘參數 箭頭函數 基本示例 for of 迴圈 for 迴圈 forEach 不支持 break for in 會把數組當作對象來遍歷 for of 支持 break 類型推斷(Type Inference) 類型相容性 模塊 概念 模塊通信: ...
  • 解構賦值 數組解構 上面的寫法等價於: 利用解構賦值交換變數: 函數參數解構: 解構剩餘參數: 也可以忽略其它參數: 或者跳過解構: 對象解構 示例一: 就像數組解構,你可以用沒有聲明的賦值: 你可以在對象里使用 語法創建剩餘變數: 屬性解構重命名 你也可以給屬性以不同的名字: 註意,這裡的冒號 不 ...
  • Hello World 新建 並寫入以下內容: 安裝編譯器: 編譯: 修改 文件中的代碼,為 greeter 函數的參數 person 加上類型聲明 : 重新編譯執行。 讓我們繼續修改: 重新編譯,你將看到如下錯誤: 介面(Interface) 類(Class) 變數聲明 作用域 重覆聲明 塊級作用 ...
  • TypeScript 介紹 TypeScript 是什麼 TypeScript 是 JavaScript 的強類型版本。然後在編譯期去掉類型和特有語法,生成純粹的 JavaScript 代碼。由於最終在瀏覽器中運行的仍然是 JavaScript,所以 TypeScript 並不依賴於瀏覽器的支持,也 ...
  • 隨著你的 Python 項目越來越多,你會發現不同的項目會需要 不同的版本的 Python 庫。同一個 Python 庫的不同版本可能不相容。虛擬環境可以為每一個項目安裝獨立的 Python 庫,這樣就可以隔離不同項目之間的 Python 庫,也可以隔離項目與操作系統之間的 Python 庫。 1. ...
  • http請求在我們實際工作中天天見,為了不重覆造輪子,現在分享一下最近的一次封裝整理,供大家參考,交流,學習! ...
  • static void AggregateExceptionsDemo() { var task1 = Task.Factory.StartNew(() => { var child1 = Task.Factory.StartNew(() => { throw new CustomException ...
一周排行
  • 1. 泛型Generic 1.1 引入泛型:延遲聲明 泛型方法聲明時,並未寫死類型,在調用的時候再指定類型。 延遲聲明:推遲一切可以推遲的。 1.2 如何聲明和使用泛型 泛型方法:方法名稱後面加上尖括弧,裡面是類型參數 類型參數實際上就是一個類型T聲明,方法就可以用這個類型T了。 如下所示: pub ...
  • 本筆記摘抄自:https://www.cnblogs.com/PatrickLiu/p/7903617.html,記錄一下學習過程以備後續查用。 一、引言 今天我們要講行為型設計模式的第三個模式--迭代器模式,先從名字上來看。迭代是遍歷的意思,迭代器可以理解為是遍歷某某的工具,遍歷什麼呢?在軟 件設 ...
  • 本筆記摘抄自:https://www.cnblogs.com/PatrickLiu/p/7928521.html,記錄一下學習過程以備後續查用。 一、引言 今天我們要講行為型設計模式的第四個模式--觀察者模式,先從名字上來看。觀察者模式可以理解為既然有“觀察者”,那肯定就有“被觀察者”了。“觀察者” ...
  • 先看核心代碼: public List<DataEntity> SearchShopSalesReport(DateTimeOffset? dateFrom, DateTimeOffset? dateTo,string groupBy) { var query = data.DataEntity / ...
  • 首先新建一個項目,名稱叫Caliburn.Micro.ActionConvertions 然後刪掉MainWindow.xaml 然後去app.xaml刪掉StartupUri這行代碼 其次,安裝Caliburn.Micro,Caliburn.Micro.Core,這兩個Nuget包,如下圖 然後新 ...
  • 一文帶你瞭解 C DLR 的世界 在很久之前,我寫了一片文章 "dynamic結合匿名類型 匿名對象傳參" ,裡面我以為DLR內部是用反射實現的。因為那時候是心中想當然的認為只有反射能夠在運行時解析對象的成員信息並調用成員方法。後來也是因為其他的事一直都沒有回過頭來把這一節知識給補上,正所謂亡羊補牢 ...
  • ​ 在C#8.0中,針對介面引入了一項新特性,就是可以指定預設實現,方便對已有實現進行擴展,也對面向Android和Swift的Api進行互操作提供了可能性。下麵我們來看看該特性的具體規則與實現。 一、主要應用場景: 在不破壞影響已有實現的情況下,可以添加新成員。這解決了在第三方已經大量使用了的介面 ...
  • 前言 通常在應用程式開發到正式上線,在這個過程中我們會分為多個階段,通常會有 開發、測試、以及正式環境等。每個環境的參數配置我們會使用不同的參數,因此呢,在ASP.NET Core中就提供了相關的環境API,方便我們更好的去做這些事情。 環境 ASP.NET Core使用ASPNETCORE_ENV ...
  • 擱置了幾天,工作忙的一塌糊塗,今天終於抽空來繼續看看MVC的知識。先來看看MVC的路由是如何處理的。以下為替代的路由: app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{ ...
  • 多用www.bing.com國際版解決代碼報錯 代碼運行的時候,報異常,國內的搜索引擎一搜, 浮誇的廣告太多,解決方案准確性不足, 盜版又很嚴重(導致一錯皆錯),方案未及時更新等詬病。 www.bing.com國際版可以關聯到: (1). 外國官網,可以獲得官方的解決方案。 (2). stackov ...
x