文章目錄
- 一、橋接模式的定義
- 二、為什么需要橋接模式?
- 三、示例代碼
一、橋接模式的定義
??橋接模式是一種結構型設計模式,它的主要作用是將抽象部分與實現部分分離,使它們能夠獨立變化。換句話說,就是把“抽象”和“實現”放到兩個獨立的類層次中,通過組合而不是繼承來連接它們。
橋接模式結構:
二、為什么需要橋接模式?
問題:
假如有一個幾何形狀Shape類, 從它能擴展出兩個子類: ? 圓形Circle和 方形Square 。 你希望對這樣的類層次結構進行擴展以使其包含顏色, 所以你打算創建名為紅色Red和 藍色Blue的形狀子類。 但是, 由于你已有兩個子類, 所以總共需要創建四個類才能覆蓋所有組合, 例如藍色圓形Blue-Circle和紅色方形Red-Square 。
在層次結構中新增形狀和顏色將導致代碼復雜程度指數增長。 例如添加三角形狀, 你需要新增兩個子類, 也就是每種顏色一個; 此后新增一種新顏色需要新增三個子類, 即每種形狀一個。 如此以往, 情況會越來越糟糕。
解決方案:
問題的根本原因是我們試圖在兩個獨立的維度——形狀與顏色——上擴展形狀類。 這在處理類繼承時是很常見的問題。
橋接模式通過將繼承改為組合的方式來解決這個問題。 具體來說, 就是抽取其中一個維度并使之成為獨立的類層次, 這樣就可以在初始類中引用這個新層次的對象, 從而使得一個類不必擁有所有的狀態和行為。
根據該方法, 我們可以將顏色相關的代碼抽取到擁有紅色和藍色兩個子類的顏色類中, 然后在形狀類中添加一個指向某一顏色對象的引用成員變量。 現在, 形狀類可以將所有與顏色相關的工作委派給連入的顏色對象。 這樣的引用就成為了形狀和顏色之間的橋梁。 此后, 新增顏色將不再需要修改形狀的類層次, 反之亦然。
橋接模式 UML 類圖:
Abstraction(形狀)|vRefinedAbstraction(圓形/矩形)|| has-avImplementor(顏色接口)|---------------------| |
ConcreteImplementorA ConcreteImplementorB(紅色) (藍色)
橋接模式的角色:
- 抽象類(Abstraction):定義抽象接口,包含一個實現類的引用。
- 擴展抽象類(RefinedAbstraction):在抽象類的基礎上擴展功能。
- 實現接口(Implementor):定義實現部分的接口。
- 具體實現類(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。