設計模式(7) 橋接模式

来源:https://www.cnblogs.com/zhixin9001/archive/2020/07/15/13308632.html
-Advertisement-
Play Games

橋接模式的概念與實現 為什麼叫橋接模式 橋接模式的適用場景 繼承是面向對象的三大特性之一,但很多時候使用繼承的結果卻不盡如人意。除了人盡皆知的緊耦合問題外,有的時候還會導致子類的快速膨脹。 設想這樣一個場景:最初設計的時候有一個類型Product,但後來隨著新需求的出現,X原因導致了它的變化,X有兩 ...


  • 橋接模式的概念與實現
  • 為什麼叫橋接模式
  • 橋接模式的適用場景

繼承是面向對象的三大特性之一,但很多時候使用繼承的結果卻不盡如人意。除了人盡皆知的緊耦合問題外,有的時候還會導致子類的快速膨脹。

設想這樣一個場景:最初設計的時候有一個類型Product,但後來隨著新需求的出現,X原因導致了它的變化,X有兩種情況,則通過繼承需要創建兩個新的子類ProductX1,ProductX2,但後來有出現了Y因素也會導致Product的變化,如果Y有三種情況,則會出現ProductX1Y1,ProductX1Y2,ProductX1Y3...等,一共2*3=6個類。

使用這種繼承的方式,如果再出現新的變化因素,或者某個變化因素出現了新的情況,都會導致子類的快速膨脹,給維護帶來很大的挑戰。

造成這個問題的根本原因是類型在沿著多個維度變化。為了應對變化,一般會通過抽象的方法,找到其中比較穩定的部分,然後抽象其行為,令客戶程式依賴於抽象而不是具體實現。同樣的道理,當一個類型同時受到多個因素變化的影響時,也通過把每個因素抽象,讓類型依賴於一系列抽象因素的辦法儘量處理這個問題,這便是橋接模式解決問題的思路。

橋接模式的概念與實現

GOF對橋接模式的描述為:
Decouple an abstraction from its implementationso that the two can vary independently.
— Design Patterns : Elements of Reusable Object-Oriented Software
橋接模式將抽象部分與它的實現部分分離,使它們都可以獨立地變化。

橋接模式的UML類圖為
橋接模式 UML類圖

示例代碼:

public interface IImpl
{
    void OperationImpl();
}

public interface IAbstraction
{
    IImpl Implementor { get; set; }
    void Operation();
}
public class ConcreteImplementatorA : IImpl
{
    public void OperationImpl()
    {
        ...
    }
}

public class ConcreteImplementatorB : IImpl
{
    public void OperationImpl()
    {
        ...
    }
}

public class RefinedAbstration : IAbstraction
{
    public IImpl Implementor { get; set; }

    public void Operation()
    {
        Implementor.OperationImpl();
    }
}

這樣子看起來還是比較抽象,再舉個具體的例子汽車-道路,目前汽車有小汽車、公車兩類,路有水泥路、石子路兩類,這樣“車在路上行駛”就會有四種情況,這個場景用橋接模式來描述的話可以是:
汽車類的抽象與實現:

public interface IVehicle
{
    string Drive();
}

public class Car : IVehicle
{
    public string Drive()
    {
        return "Car";
    }
}

public class Bus : IVehicle
{
    public string Drive()
    {
        return "Bus";
    }
}

通過橋接模式關聯道路與汽車:

public abstract class Road
{
    protected IVehicle vehicle;
    public Road(IVehicle vehicle)
    {
        this.vehicle = vehicle;
    }

    public abstract string DriveOnRoad();
}

public class UnpavedRoad : Road
{
    public UnpavedRoad(IVehicle vehicle) : base(vehicle) { }
    public override string DriveOnRoad()
    {
        return vehicle.Drive() + " is on Unpaved Road";
    }
}

public class CementRoad : Road
{
    public CementRoad(IVehicle vehicle) : base(vehicle) { }
    public override string DriveOnRoad()
    {
        return vehicle.Drive() + " is on Cement Road";
    }
}

調用:

IVehicle vehicle = new Car();
Road road = new CementRoad(vehicle);
Console.WriteLine(road.DriveOnRoad());
// Car is on Cement Road
Speed speed = new FastSpeed(road);
Console.WriteLine(speed.DriveWithSpeed());
// Car is on Cement Road,

在這裡Road依賴的是IVehivle抽象,具體的汽車實現在調用的時候決定。
對比直接繼承出四種類型的方式,這樣做的好處貌似並不明顯,還是需要四個類,而且更複雜,但如果汽車或者道路類型繼續增加,或者引入了別的變化因素,情況就不一樣了。

為什麼叫橋接模式

有個疑惑是關於橋接模式的名稱的,為什麼叫橋接模式呢?之前的工廠、適配器等名稱都挺形象的,但橋接模式好像有點不同,這要從橋接模式解決問題的思路說起,橋接模式更多的是提示我們面向對象的設計分解方式,可以概括為三步:

  • 第一步,把依賴具體變成依賴抽象。
  • 第二步,如果對象同時沿著多個維度變化,那就順次展開抽象因素。
  • 第三步,為每個抽象因素提供具體實現。

示意圖:
分解

到了第三步,就可以大概看出橋接模式的形象化表示了,IX、IY和IZ構成連接部(被稱為支座),而每個具體類形成了一個個橋墩。
所以橋接模式,是以抽象之間的依賴為橋面、以具體實現為橋墩,建起了一座連接需求與實現的橋梁。

橋接模式的適用場景

  • 如果一個系統需要在構件的抽象化角色和具體化角色之間增加更多的靈活性,避免在兩個層次之間建立靜態的聯繫。
  • 設計要求實現化角色的任何改變不應當影響客戶端,或者說實現化角色的改變對客戶端是完全透明的。
  • 一個構件有多於一個的抽象化角色和實現化角色,系統需要它們之間進行動態耦合。
  • 雖然在系統中使用繼承是沒有問題的,但是由於抽象化角色和具體化角色需要獨立變化,設計要求需要獨立管理這兩者。

參考書籍:
王翔著 《設計模式——基於C#的工程化實現及擴展》


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

-Advertisement-
Play Games
更多相關文章
  • git config --global http.sslverify false ...
  • var exp=undefinded; if(typeof(exp)=="undefined") { //變數是undefined的處理 } typeof 返回的是字元串,有六種可能:"number"、"string"、"boolean"、"object"、"function"、"undefined ...
  • 移動WEB開發的rem佈局 目標(目錄) 能夠使用rem單位 能夠使用媒體查詢的基本語法 能夠使用Less的基本語法 能夠使用Less中的嵌套 能夠使用Less中的運算 能夠使用2種rem適配方案 思考:1、頁面佈局文字能夠隨著屏幕大小的變化而變化? 2、流式佈局和flex佈局主要針對於寬度佈局,那 ...
  • layui table有多行數據,通過外部輸入內容,需要定位到指定行,選中改行,對改行進行操作。 實現效果: HTML代碼: 1 <body> 2 <div class="layui-fluid"> 3 <input type="text" id="txt_id" /> 4 <table class ...
  • 價格便宜50-100 有圖的(仿站無需圖) 包動畫效果 也可以包介面對接 太複雜的頁麵價格另算 有意加qq896705559 另出體溫單源碼 http://106.12.212.110:8077/#/ 線上地址 包括折線圖 虛線實線 下垂線 陰影區域等 自定義每日時間 按照醫院標準編寫 ...
  • 在“JavaScript圖形實例:曲線方程”一文中,我們給出了15個曲線方程繪製圖形的實例。這些曲線都是根據其曲線方程,在[0,2π]區間取一系列角度值,根據給定角度值計算對應的各點坐標,然後在計算出的坐標位置描點,從而繪製出曲線。 我們可以將曲線的繪製過程動態展示出來。 例如,對於星形線的繪製,編 ...
  • 許可權管理系統中,菜單也屬於許可權控制的一個資源,應該直接應用於角色,和許可權功能點一樣,屬於角色控制的一環。不同角色用戶,登錄系統後,出現的系統菜單是不同的。在VUE+Element 前端中,我們菜單結合路由集合,實現可訪問路由的過濾,也就實現了對應角色菜單的展示和可訪問路由的控制,詳細可以參考隨筆《循... ...
  • 2020 年真的是災禍頻發,但是在各類前端框架上,依舊是在穩步的推進。近日 Vue 團隊更新了關於 Vue 3 的最新狀態,尤大新增了三個語法糖特性,它們將用於優化 SFC 的開發體驗,你會有興趣嘗鮮試試麽~ 登高遠眺 天高地迥,覺宇宙之無窮 前端框架 Vue 3: 2020 年中的狀態更新 近日 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...