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 ...
一周排行
  • 本文將介紹如何在.NET Core3環境下使用MVVM框架Prism的使用區域管理器對於View的管理 一.區域管理器 我們在之前的Prism系列構建了一個標準式Prism項目,這篇文章將會講解之前項目中用到的利用區域管理器更好的對我們的View進行管理,同樣的我們來看看官方給出的模型圖: 現在我們 ...
  • 前言: gRPC預設是ProtoFirst的,即先寫 proto文件,再生成代碼,需要人工維護proto,生成的代碼也不友好,所以出現了gRPC CodeFirst,下麵來說說我們是怎麼實現gRPC CodeFirst 目錄: 實現和WCF一樣的CodeFirst (1). 實現gRPC CodeF ...
  • [toc] 1.背景 接上篇文章 "深入淺出C 結構體——封裝乙太網心跳包的結構為例" ,使用結構體性能不佳,而且也說明瞭原因。本篇文章詳細描述了以類來封裝網路心跳包的優缺點,結果大大提升瞭解析性能。 2.用類來封裝乙太網心跳包的優缺點 2.1.優點 + 可以在類里直接new byte[],即直接實 ...
  • VS2013如何轉成VS2010且不會出現此項目與Visual Studio的當前版本不相容的報錯 解決方法: 1.用記事本打開解決方案文件“解決方案名.sln”,然後修改最上面兩行為如下代碼:Microsoft Visual Studio Solution File, Format Version ...
  • 傳遞數據至部分視圖: 在ps.cshtml中get到上面高亮的參數: ...
  • 三、C#數據類型 3.1.變數 聲明->賦值->使用 作用域:變數作用域為包含它的大括弧內 3.2.常量 1)const 數據類型 常量名稱 = 常量值 聲明常量時一定要賦值 2)@作用 輸出轉義字元 @"Hello World\n" 讓字元串換行 關鍵字用作標識符 @namespace @clas ...
  • 四、C#表達式與運算符 4.1.表達式 操作數+運算符 4.2.數學運算符 var++ 先用後加 ++var 先加後用 4.3.賦值運算符 略 4.4.關係運算符 結果只會是bool類型 1)對象的不同 數值類型比較兩個數的大小 字元類比較Unicode編碼大小,'A'=65 'a'=97 '0'= ...
  • 下麵的靜態代碼中: 現在想把箭頭所指的值,改為動態。 根據不同條件,它將有可能是1,或是3或是2或是5等。 ...
  • 使用Xaml+C#,使WPF/UWP運行在Linux和Mac上 ...
  • 前言 C 的lambda和Linq可以說是一大亮點,C 的Lambda無處不在,Linq在數據查詢上也有著舉足輕重的地位。 那麼什麼是Linq呢,Linq是 (語言集成查詢)的縮寫,可以對本地對象 集合 或者遠程數據源進行結構化的查詢操作。 那什麼又是Lambda呢?嗯,簡單來講就是匿名函數,我們不 ...
x