設計模式:橋接模式(Bridge Pattern)

文章目錄

    • 一、橋接模式的定義
    • 二、為什么需要橋接模式?
    • 三、示例代碼

一、橋接模式的定義

??橋接模式是一種結構型設計模式,它的主要作用是將抽象部分與實現部分分離,使它們能夠獨立變化。換句話說,就是把“抽象”和“實現”放到兩個獨立的類層次中,通過組合而不是繼承來連接它們。

橋接模式結構:
在這里插入圖片描述

二、為什么需要橋接模式?

問題:
假如有一個幾何形狀Shape類, 從它能擴展出兩個子類: ? 圓形Circle和 方形Square 。 你希望對這樣的類層次結構進行擴展以使其包含顏色, 所以你打算創建名為紅色Red和 藍色Blue的形狀子類。 但是, 由于你已有兩個子類, 所以總共需要創建四個類才能覆蓋所有組合, 例如藍色圓形Blue-Circle和紅色方形Red-Square 。
在這里插入圖片描述

在層次結構中新增形狀和顏色將導致代碼復雜程度指數增長。 例如添加三角形狀, 你需要新增兩個子類, 也就是每種顏色一個; 此后新增一種新顏色需要新增三個子類, 即每種形狀一個。 如此以往, 情況會越來越糟糕。

解決方案:
問題的根本原因是我們試圖在兩個獨立的維度——形狀與顏色——上擴展形狀類。 這在處理類繼承時是很常見的問題。
橋接模式通過將繼承改為組合的方式來解決這個問題。 具體來說, 就是抽取其中一個維度并使之成為獨立的類層次, 這樣就可以在初始類中引用這個新層次的對象, 從而使得一個類不必擁有所有的狀態和行為。
在這里插入圖片描述
根據該方法, 我們可以將顏色相關的代碼抽取到擁有紅色和藍色兩個子類的顏色類中, 然后在形狀類中添加一個指向某一顏色對象的引用成員變量。 現在, 形狀類可以將所有與顏色相關的工作委派給連入的顏色對象。 這樣的引用就成為了形狀和顏色之間的橋梁。 此后, 新增顏色將不再需要修改形狀的類層次, 反之亦然。

橋接模式 UML 類圖:

        Abstraction(形狀)|vRefinedAbstraction(圓形/矩形)|| has-avImplementor(顏色接口)|---------------------|                   |
ConcreteImplementorA   ConcreteImplementorB(紅色)                 (藍色)

橋接模式的角色:

  1. 抽象類(Abstraction):定義抽象接口,包含一個實現類的引用。
  2. 擴展抽象類(RefinedAbstraction):在抽象類的基礎上擴展功能。
  3. 實現接口(Implementor):定義實現部分的接口。
  4. 具體實現類(ConcreteImplementor):實現具體的實現邏輯。

示例:形狀 + 顏色

#include <iostream>
#include <memory>
using namespace std;// 實現部分(Implementor)
class Color {
public:virtual void applyColor() = 0;virtual ~Color() = default;
};// 具體實現類
class Red : public Color {
public:void applyColor() override {cout << "Red" << endl;}
};class Blue : public Color {
public:void applyColor() override {cout << "Blue" << endl;}
};// 抽象部分(Abstraction)
class Shape {
protected:shared_ptr<Color> color; // 橋接
public:Shape(shared_ptr<Color> c) : color(c) {}virtual void draw() = 0;virtual ~Shape() = default;
};// 擴展抽象類
class Circle : public Shape {
public:Circle(shared_ptr<Color> c) : Shape(c) {}void draw() override {cout << "Drawing Circle in ";color->applyColor();}
};class Rectangle : public Shape {
public:Rectangle(shared_ptr<Color> c) : Shape(c) {}void draw() override {cout << "Drawing Rectangle in ";color->applyColor();}
};// 測試
int main() {shared_ptr<Color> red = make_shared<Red>();shared_ptr<Color> blue = make_shared<Blue>();shared_ptr<Shape> circle = make_shared<Circle>(red);shared_ptr<Shape> rectangle = make_shared<Rectangle>(blue);circle->draw();     // Drawing Circle in Redrectangle->draw();  // Drawing Rectangle in Bluereturn 0;
}

三、示例代碼

示例說明:
用圖形(圓形、矩形) × 繪制引擎(QPainter 繪制、QSvgGenerator 繪制)

  • 抽象部分(Shape):圖形(Circle、Rectangle)
  • 實現部分(DrawAPI):繪制引擎(PainterDraw、SvgDraw)
  • 橋接:Shape 持有 DrawAPI 的指針,可以自由組合。

代碼示例:

#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <QSvgGenerator>
#include <memory>
#include <iostream>// 實現部分接口(DrawAPI)
class DrawAPI {
public:virtual void drawCircle(QWidget *widget, int x, int y, int r) = 0;virtual void drawRect(QWidget *widget, int x, int y, int w, int h) = 0;virtual ~DrawAPI() = default;
};// 具體實現1:用 QPainter 繪制
class PainterDraw : public DrawAPI {
public:void drawCircle(QWidget *widget, int x, int y, int r) override {QPainter p(widget);p.setPen(Qt::red);p.drawEllipse(QPoint(x, y), r, r);}void drawRect(QWidget *widget, int x, int y, int w, int h) override {QPainter p(widget);p.setPen(Qt::blue);p.drawRect(x, y, w, h);}
};// 具體實現2:繪制到 SVG 文件
class SvgDraw : public DrawAPI {
public:void drawCircle(QWidget *widget, int x, int y, int r) override {QSvgGenerator generator;generator.setFileName("circle.svg");generator.setSize(QSize(widget->width(), widget->height()));QPainter p(&generator);p.setPen(Qt::red);p.drawEllipse(QPoint(x, y), r, r);}void drawRect(QWidget *widget, int x, int y, int w, int h) override {QSvgGenerator generator;generator.setFileName("rect.svg");generator.setSize(QSize(widget->width(), widget->height()));QPainter p(&generator);p.setPen(Qt::blue);p.drawRect(x, y, w, h);}
};// 抽象部分(Shape)
class Shape {
protected:std::shared_ptr<DrawAPI> drawApi;
public:Shape(std::shared_ptr<DrawAPI> api) : drawApi(api) {}virtual void draw(QWidget *widget) = 0;virtual ~Shape() = default;
};// 擴展抽象:圓形
class Circle : public Shape {int x, y, r;
public:Circle(int _x, int _y, int _r, std::shared_ptr<DrawAPI> api): Shape(api), x(_x), y(_y), r(_r) {}void draw(QWidget *widget) override {drawApi->drawCircle(widget, x, y, r);}
};// 擴展抽象:矩形
class Rectangle : public Shape {int x, y, w, h;
public:Rectangle(int _x, int _y, int _w, int _h, std::shared_ptr<DrawAPI> api): Shape(api), x(_x), y(_y), w(_w), h(_h) {}void draw(QWidget *widget) override {drawApi->drawRect(widget, x, y, w, h);}
};// 測試窗口
class BridgeWidget : public QWidget {std::shared_ptr<Shape> shape1;std::shared_ptr<Shape> shape2;
public:BridgeWidget(QWidget *parent = nullptr) : QWidget(parent) {auto painter = std::make_shared<PainterDraw>();auto svg = std::make_shared<SvgDraw>();// 圓形用 Painter 畫在窗口shape1 = std::make_shared<Circle>(100, 100, 50, painter);// 矩形輸出到 rect.svgshape2 = std::make_shared<Rectangle>(50, 150, 120, 80, svg);}protected:void paintEvent(QPaintEvent *event) override {shape1->draw(this);  // 窗口繪制shape2->draw(this);  // 同時生成 rect.svg}
};int main(int argc, char *argv[]) {QApplication app(argc, argv);BridgeWidget w;w.resize(300, 300);w.show();return app.exec();
}

實現效果:

  • 窗口中會顯示一個紅色的圓形(QPainter 繪制)。
  • 同時會在程序目錄下生成 rect.svg 文件,里面保存一個藍色矩形(SvgDraw 繪制)。
  • Shape(抽象部分) 和 DrawAPI(實現部分) 解耦。
  • 想要支持新的繪制方式(比如 OpenGLDraw),只需要新建一個實現類,不影響 Shape。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/94771.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/94771.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/94771.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

AI-Agent 深度科普:從概念到架構、應用與未來趨勢

目錄 一、Agent 究竟是什么&#xff1f; 二、Agent 的核心組成模塊 三、Agent 架構類型與協作模式 單智能體&#xff08;Single-Agent&#xff09; 多智能體協作&#xff08;Multi-Agent&#xff09; 人機協作&#xff08;Human-in-the-loop&#xff09; 四、Agent 的能…

企業分支上云的常見誤區與糾正方案

數字化轉型的浪潮下&#xff0c;“上云”幾乎成為所有企業的必答題。然而&#xff0c;在實際落地中&#xff0c;很多企業發現&#xff1a;總部上云容易&#xff0c;分支上云卻困難重重。不是網絡體驗不穩定&#xff0c;就是合規風險頻出&#xff0c;要么就是成本失控。這其中很…

深入解析函數棧幀創建與銷毀

目錄 一、函數棧幀&#xff08;Stack Frame&#xff09;整理 1、核心概念 2、為什么需要函數棧幀&#xff1f; 3、函數棧幀的主要內容 二、理解函數棧幀能解決的核心問題 1、局部變量的生命周期與本質 2、函數調用的參數傳遞機制 3、函數返回值的傳遞 三、函數棧幀的創…

廣告牌安全監測系統綜合解決方案

一、方案背景 廣告牌作為城市戶外廣告的重要載體&#xff0c;廣泛分布于城市道路、商業區及交通樞紐等人流密集區域。由于長期暴露在自然環境中&#xff0c;廣告牌面臨著風荷載、雨雪侵蝕、溫度變化等多重因素的影響&#xff0c;其結構安全性和穩定性直接關系到公共安全。近年來…

MII的原理

一、介紹 MII 是 Media Independent Interface&#xff08;媒體獨立接口&#xff09; 的縮寫&#xff0c;是一種用于連接網絡物理層&#xff08;PHY&#xff09;芯片和數據鏈路層&#xff08;MAC&#xff09;芯片的標準硬件接口&#xff0c;核心作用是讓不同類型的物理層&…

【Excel】Excel的工作場景

一、Excel的發展歷史 1.1 版本迭代周期 自Excel 2019版本起&#xff0c;微軟將更新周期穩定在每3年一次&#xff0c;而3年的周期剛好平衡了創新與穩定&#xff1a;既能緊跟大數據時代下用戶對自動化、智能化處理的需求&#xff08;比如近年數據量激增帶來的批量處理需求&#x…

nestjs 連接redis

1、下載npm install --save nestjs-modules/ioredis ioredis2、全局模塊中引用RedisModule.forRootAsync({useFactory: (configService: ConfigService) > {return {type:"single",url: configService.get(redis.url) };},inject: [ConfigService], }),整體如下&…

需求管理需要哪些角色配合

需求管理是項目管理的關鍵組成部分&#xff0c;它確保項目目標得到準確理解并能順利實現。有效的需求管理需要多個角色的緊密配合&#xff0c;包括項目經理、產品經理、需求分析師、開發人員、測試人員等。這些角色共同協作&#xff0c;確保需求從收集、分析、實施到驗證的每一…

SqlHelper類的方法詳細解讀和使用示例

在 C# 數據庫編程中&#xff0c;SqlHelper類是簡化 SQL Server 操作的重要工具&#xff0c;它封裝了ADO.NET的底層細節&#xff0c;讓開發者能更專注于業務邏輯。以下從方法原理、使用示例和實戰技巧三個方面進行詳細說明。 一、SqlHelper 核心方法原理與對比 SqlHelper的方法…

智能一卡通系統通過集成身份識別、權限管理、數據聯動等技術,實現多場景一體化管理。以下是多奧基于最新技術趨勢和應用案例的系統解析

智能一卡&#xff08;碼、臉&#xff09;通系統包括消費系統、梯控、門禁、停車場管理、訪客機等&#xff0c;需要了解這些系統的集成應用和最新技術發展。多奧打算從以下幾個維度來講解。智能一卡通系統的整體架構和主要功能模塊各子系統(門禁、梯控、停車場、訪客管理等)的技…

嵌入式學習日志————USART串口協議

1.通信接口通信的目的&#xff1a;將一個設備的數據傳送到另一個設備&#xff0c;擴展硬件系統通信協議&#xff1a;制定通信的規則&#xff0c;通信雙方按照協議規則進行數據收發名稱引腳雙工時鐘電平設備USARTTX&#xff08;數據發送腳&#xff09;、RX&#xff08;數據接收腳…

微軟硬件筆試面試核心題型詳細解析

微軟硬件筆試面試核心題型詳細解析 本專欄預計更新90期左右。當前第42期-筆試面試核心題型詳細解析. 本文一共4個章節,核心內容如下。 微軟作為全球頂尖的科技公司,其硬件工程師的選拔標準極高。筆試不僅考察扎實的理論基礎,更注重解決實際問題的能力、對新技術的理解以…

CMake構建學習筆記21-通用的CMake構建腳本

在之前使用CMake構建程序的腳本&#xff08;CMake構建學習筆記-目錄&#xff09;中&#xff0c;大部分內容都有比較強的相似性&#xff0c;那么是不是可以這些相似的內容提取出來作為一個單獨的腳本&#xff0c;在構建具體的程序的時候再去調用這個腳本呢&#xff1f;這樣做的好…

無人機和無人系統的計算機視覺-人工智能無人機

無人機和無人系統的計算機視覺-人工智能無人機將計算機視覺與無人系統相結合&#xff0c;可以提升其自主或半自主執行復雜任務的能力。這些系統將圖像數據與其他機載傳感器&#xff08;例如 GNSS/GPS、IMU、LiDAR 和熱像儀&#xff09;融合&#xff0c;以解讀周圍環境并執行精確…

【開題答辯全過程】以 基于hadoop架構的教學過程監控系統為例,包含答辯的問題和答案

個人簡介&#xff1a;一名14年經驗的資深畢設內行人&#xff0c;語言擅長Java、php、微信小程序、Python、Golang、安卓Android等開發項目包括大數據、深度學習、網站、小程序、安卓、算法。平常會做一些項目定制化開發、代碼講解、答辯教學、文檔編寫、也懂一些降重方面的技巧…

坎坷基金路

2025年8月27日上午10:59從基金委官網上中外合作入口查到自己的基金中了。心情頓時五味雜陳&#xff0c;回想起寫基金忙碌的9個月&#xff0c;各位專家對我的指導&#xff0c;嘴角楠楠的說&#xff1a;感恩。自己覺著比較重要的幾個點&#xff1a;1、立意必須基于自己的過往研究…

[n8n]

docs&#xff1a;n8n工作流管理系統 本項目幫助管理和探索n8n工作流。 它能自動掃描和分析工作流文件&#xff0c;提取關鍵信息如名稱、觸發器和關聯服務。 所有數據將存入可搜索的數據庫&#xff0c;并通過REST API提供訪問。 可以快速定位特定工作流、查看詳細描述&#xff0…

[手寫系列]Go手寫db — — 第二版

[手寫系列]Go手寫db — — 第二版 第一版文章&#xff1a;[手寫系列]Go手寫db — — 完整教程 整體項目Github地址&#xff1a;https://github.com/ziyifast/ZiyiDB請大家多多支持&#xff0c;也歡迎大家star??和共同維護這個項目~ 本文主要介紹如何在 ZiyiDB 第一版的基礎上…

私有化大模型基礎知識

私有化大模型基礎知識 文章目錄私有化大模型基礎知識0x01.開源閉源2. 數據成本&#xff1a;昂貴且隱形的開銷3. 研發投入&#xff1a;人力與時間成本總結&#xff1a;總成本量化更重要的是&#xff1a;持續投入和機會成本0x02.模型大小0x03.模型參數0x04.CPU和GPU0x05.GPU和模型…

Django時區處理

Django 的時區處理機制是為了確保在全球部署應用時&#xff0c;時間數據始終一致、可控&#xff0c;并能根據用戶或系統需求靈活轉換。下面我來系統地拆解一下 Django 的時區處理方式&#xff0c;幫你掌握從配置到實際應用的全過程。&#x1f9ed; 1. 基礎配置&#xff1a;USE_…