C++ 桥接模式 (Bridge Pattern)

C++ 桥接模式 (Bridge Pattern)

flyfish

桥接模式是一种结构型设计模式,旨在将抽象部分与它的实现部分分离,使它们可以独立地变化。桥接模式可以使一个类的功能层次结构与实现层次结构分离。它通过引入一个中间接口(桥接接口)将具体的实现与抽象分离,适用于需要跨多个不同维度来扩展的系统。最简单的说法就是通过一个桥梁来连接两个独立变化的部分,使它们可以独立地变化和扩展。

看代码例子可以更清晰的理解桥接模式 (Bridge Pattern)

在以下情况下使用桥接模式:

当不希望在抽象和实现之间有紧密的耦合:使用桥接模式可以将抽象和实现分离,使得它们可以独立变化。

当希望在运行时更改实现:可以动态地选择不同的实现,例如不同的绘图API或不同的通信协议。当希望一个类在多个维度上变化时,使用桥接模式。当一个类有多个可能的实现方式,并且这些实现方式可以动态切换时,使用桥接模式。

当希望通过组合而不是继承来扩展类的功能:桥接模式比传统的继承更灵活,可以避免复杂的类层次结构。

桥接模式的 C++ 代码示例

绘制圆形,并结合具体的绘图API来说明桥接模式的用法。

功能层次结构(抽象部分):

Shape:抽象类,定义了形状的接口,包含一个指向DrawingAPI的引用。

CircleShape:具体的形状类,继承自Shape,实现了具体的圆形绘制和调整大小的功能。

实现层次结构(具体实现部分):

DrawingAPI:抽象接口类,定义了绘制圆形的接口。

DrawingAPI01和DrawingAPI02:具体实现类,分别实现了不同的绘制圆形的方法。

c 复制代码
#include <iostream>
#include <string>
#include <vector>

// 抽象接口类:绘图API,定义绘制圆的接口
class DrawingAPI {
public:
    virtual ~DrawingAPI() = default;
    // 纯虚函数,绘制圆形,具体实现由子类提供
    virtual std::string DrawCircle(float x, float y, float radius) const = 0;
};

// 具体实现类01:使用API01绘制圆形
class DrawingAPI01 : public DrawingAPI {
public:
    std::string DrawCircle(float x, float y, float radius) const override {
        return "API01.circle at " + std::to_string(x) + ":" + std::to_string(y) +
               " - radius: " + std::to_string(radius);
    }
};

// 具体实现类02:使用API02绘制圆形
class DrawingAPI02 : public DrawingAPI {
public:
    std::string DrawCircle(float x, float y, float radius) const override {
        return "API02.circle at " + std::to_string(x) + ":" + std::to_string(y) +
               " - radius: " + std::to_string(radius);
    }
};

// 抽象类:形状,包含一个指向绘图API的引用
class Shape {
public:
    // 构造函数,初始化绘图API引用
    Shape(const DrawingAPI& drawing_api) : drawing_api_(drawing_api) {}
    virtual ~Shape() = default;

    // 纯虚函数,绘制形状,由子类实现
    virtual std::string Draw() const = 0;
    // 纯虚函数,按百分比调整大小,由子类实现
    virtual float ResizeByPercentage(const float percent) = 0;

protected:
    const DrawingAPI& drawing_api_; // 绘图API引用
};

// 具体实现类:圆形
class CircleShape : public Shape {
public:
    // 构造函数,初始化圆形位置、半径和绘图API
    CircleShape(float x, float y, float radius, const DrawingAPI& drawing_api)
        : Shape(drawing_api), x_(x), y_(y), radius_(radius) {}

    // 绘制圆形,调用绘图API的DrawCircle方法
    std::string Draw() const override {
        return drawing_api_.DrawCircle(x_, y_, radius_);
    }

    // 按百分比调整圆形的半径
    float ResizeByPercentage(const float percent) override {
        return radius_ *= (1.0f + percent / 100.0f);
    }

private:
    float x_, y_, radius_; // 圆形的位置和半径
};

int main(int argc, char** argv) {
    const DrawingAPI01 api1{}; // 创建绘图API01实例
    const DrawingAPI02 api2{}; // 创建绘图API02实例
    std::vector<CircleShape> shapes {
        // 创建圆形实例,使用不同的绘图API
        CircleShape{1.0f, 2.0f, 3.0f, api1},
        CircleShape{5.0f, 7.0f, 11.0f, api2}
    };

    // 调整圆形大小并绘制
    for (auto& shape: shapes) {
        shape.ResizeByPercentage(2.5); // 调整半径
        std::cout << shape.Draw() << std::endl; // 绘制圆形
    }

    return 0;
}

桥接模式中的类在多个维度上的变化,扩展形状的种类和绘图API的实现

  1. 形状的种类(Shape) :可以有不同的形状,如圆形(CircleShape)、矩形(RectangleShape)等。这个维度代表了形状的多样性。

  2. 绘图API的实现(DrawingAPI) :可以有不同的绘图实现,如DrawingAPI01、DrawingAPI02等。这个维度代表了绘图实现的多样性。

通过将这两个维度的变化分离,可以独立地扩展形状的种类和绘图API的实现,而不需要修改现有代码。这体现了桥接模式的灵活性。

代码中的多个维度变化的具体实现

1. 形状的变化

形状的变化体现在不同的Shape子类中:

cpp 复制代码
class Shape {
public:
    Shape(const DrawingAPI& drawing_api) : drawing_api_(drawing_api) {}
    virtual ~Shape() = default;

    virtual std::string Draw() const = 0;
    virtual float ResizeByPercentage(const float percent) = 0;

protected:
    const DrawingAPI& drawing_api_;
};

class CircleShape : public Shape {
public:
    CircleShape(float x, float y, float radius, const DrawingAPI& drawing_api)
        : Shape(drawing_api), x_(x), y_(y), radius_(radius) {}

    std::string Draw() const override {
        return drawing_api_.DrawCircle(x_, y_, radius_);
    }

    float ResizeByPercentage(const float percent) override {
        return radius_ *= (1.0f + percent / 100.0f);
    }

private:
    float x_, y_, radius_;
};

可以进一步扩展形状类,例如添加一个矩形类:

cpp 复制代码
class RectangleShape : public Shape {
public:
    RectangleShape(float x, float y, float width, float height, const DrawingAPI& drawing_api)
        : Shape(drawing_api), x_(x), y_(y), width_(width), height_(height) {}

    std::string Draw() const override {
        return drawing_api_.DrawRectangle(x_, y_, width_, height_);
    }

    float ResizeByPercentage(const float percent) override {
        width_ *= (1.0f + percent / 100.0f);
        height_ *= (1.0f + percent / 100.0f);
        return width_ * height_;
    }

private:
    float x_, y_, width_, height_;
};
2. 绘图API增加绘制矩阵的函数

绘图API的变化体现在不同的DrawingAPI实现类中:

cpp 复制代码
class DrawingAPI {
public:
    virtual ~DrawingAPI() = default;
    virtual std::string DrawCircle(float x, float y, float radius) const = 0;
    virtual std::string DrawRectangle(float x, float y, float width, float height) const = 0;
};

class DrawingAPI01 : public DrawingAPI {
public:
    std::string DrawCircle(float x, float y, float radius) const override {
        return "API01.circle at " + std::to_string(x) + ":" + std::to_string(y) +
               " - radius: " + std::to_string(radius);
    }

    std::string DrawRectangle(float x, float y, float width, float height) const override {
        return "API01.rectangle at " + std::to_string(x) + ":" + std::to_string(y) +
               " - width: " + std::to_string(width) + ", height: " + std::to_string(height);
    }
};

class DrawingAPI02 : public DrawingAPI {
public:
    std::string DrawCircle(float x, float y, float radius) const override {
        return "API02.circle at " + std::to_string(x) + ":" + std::to_string(y) +
               " - radius: " + std::to_string(radius);
    }

    std::string DrawRectangle(float x, float y, float width, float height) const override {
        return "API02.rectangle at " + std::to_string(x) + ":" + std::to_string(y) +
               " - width: " + std::to_string(width) + ", height: " + std::to_string(height);
    }
};

运行时选择不同的实现

在主程序中,我们可以在运行时选择不同的绘图API实现,并且可以独立地使用不同的形状对象:

cpp 复制代码
int main(int argc, char** argv) {
    const DrawingAPI01 api1{};
    const DrawingAPI02 api2{};
    std::vector<Shape*> shapes {
        new CircleShape{1.0f, 2.0f, 3.0f, api1},
        new RectangleShape{5.0f, 7.0f, 11.0f, 13.0f, api2}
    };

    for (auto shape : shapes) {
        shape->ResizeByPercentage(2.5);
        std::cout << shape->Draw() << std::endl;
        delete shape;
    }

    return 0;
}

在这个例子中,CircleShapeRectangleShape 代表形状的多样性(一个维度),而 DrawingAPI01DrawingAPI02 代表绘图API实现的多样性(另一个维度)。这样通过一个桥梁来连接两个独立变化的部分,使它们可以独立地变化和扩展。

相关推荐
汉克老师2 小时前
CSP-J 2026 初赛试题解析(第一部分:选择题(8-15))精讲
c++·csp-j·小学生·学c++编程
wabs6662 小时前
关于二叉树【力扣572.另一棵树的子树的思考】
数据结构·c++·算法·leetcode·二叉树
风合星语4 小时前
2026 ROS 2 Lyrical C++ 入门(五):Action 实战——任务反馈、取消与超时处理
c++·机器人·ros2·异步编程·lyrical
91刘仁德4 小时前
C++ 继承和多态 设计模式
c语言·c++·笔记
库玛西5 小时前
哈夫曼树与前缀编码:数据压缩的贪心核心
c语言·c++·笔记·考研
别动我齐刘海5 小时前
ROS2 Jazzy + C++ 实战路线——进阶学习3
c++·人工智能·vscode·python·算法·机器学习·机器人
0+1115 小时前
算法 --滑动窗口
c++·算法·leetcode
stolentime5 小时前
(有原题)CSP-S2026第一轮试题(附答案解析、markdown源码)
c++·csp
m0_734571765 小时前
深入理解C++ RAII
开发语言·c++
hetao17338376 小时前
2026-09-18 hetao1733837 的刷题记录
c++·算法