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实现的多样性(另一个维度)。这样通过一个桥梁来连接两个独立变化的部分,使它们可以独立地变化和扩展。

相关推荐
versatile_zpc6 分钟前
C++初阶:类和对象(上)
开发语言·c++
小鱼仙官12 分钟前
MFC IDC_STATIC控件嵌入一个DIALOG界面
c++·mfc
神仙别闹14 分钟前
基本MFC类框架的俄罗斯方块游戏
c++·游戏·mfc
娅娅梨1 小时前
C++ 错题本--not found for architecture x86_64 问题
开发语言·c++
兵哥工控1 小时前
MFC工控项目实例二十九主对话框调用子对话框设定参数值
c++·mfc
我爱工作&工作love我1 小时前
1435:【例题3】曲线 一本通 代替三分
c++·算法
娃娃丢没有坏心思2 小时前
C++20 概念与约束(2)—— 初识概念与约束
c语言·c++·现代c++
lexusv8ls600h2 小时前
探索 C++20:C++ 的新纪元
c++·c++20
lexusv8ls600h2 小时前
C++20 中最优雅的那个小特性 - Ranges
c++·c++20
白-胖-子2 小时前
【蓝桥等考C++真题】蓝桥杯等级考试C++组第13级L13真题原题(含答案)-统计数字
开发语言·c++·算法·蓝桥杯·等考·13级