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

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

本筆記摘抄自: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實現代碼的變化,讓客戶端更穩定,所以意圖才說是講抽象部分和它的實現部分隔離。


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

-Advertisement-
Play Games
更多相關文章
  •   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 ...
一周排行
    -Advertisement-
    Play Games
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...