一、桥接模式核心原理(通用)
桥接模式(Bridge Pattern)是结构型设计模式 ,核心思想是:将抽象部分与实现部分解耦,使两者可以独立变化。
它解决的核心问题是:当一个类存在两个或多个独立变化的维度(比如「设备类型」和「品牌」、「图形形状」和「颜色」)时,多层继承会导致类数量呈指数级增长(类爆炸),而桥接模式通过「组合代替继承」,将两个维度拆分为独立的层级,通过「桥」(对象引用)连接,让每个维度可以独立扩展。
核心角色(C++ 实现中对应概念)
| 角色名称 | 作用 | C++ 实现形式 |
|---|---|---|
| 实现化(Implementor) | 定义实现层的通用接口,提供基础操作 | 纯虚类(接口类) |
| 具体实现化(ConcreteImplementor) | 实现 Implementor 接口,提供具体的基础操作 | 普通类(继承 Implementor) |
| 抽象化(Abstraction) | 定义抽象层接口,持有 Implementor 对象的引用(桥接核心),定义高层逻辑 | 抽象类(含 Implementor 指针) |
| 扩展抽象化(RefinedAbstraction) | 继承 Abstraction,细化抽象层接口,实现具体业务逻辑 | 普通类(继承 Abstraction) |
二、C++ 代码示例(图形绘制:形状 + 颜色)
以「图形形状(抽象维度)」和「颜色(实现维度)」为例:
- 抽象维度:圆形、矩形(可扩展新形状);
- 实现维度:红色、蓝色(可扩展新颜色)。
这个场景中,形状和颜色是两个独立变化的维度,用桥接模式可以避免创建「红色圆形、蓝色圆形、红色矩形、蓝色矩形」等冗余类。
步骤 1:定义实现化接口(颜色接口)
cpp
#include <iostream>
#include <string>
// 实现化(Implementor):颜色接口(纯虚类)
class Color {
public:
// 纯虚函数:获取颜色名称
virtual std::string getColorName() const = 0;
// 虚析构函数:确保子类析构正常
virtual ~Color() = default;
};
步骤 2:实现具体实现化类(具体颜色)
cpp
// 具体实现化1:红色
class Red : public Color {
public:
std::string getColorName() const override {
return "红色";
}
};
// 具体实现化2:蓝色
class Blue : public Color {
public:
std::string getColorName() const override {
return "蓝色";
}
};
步骤 3:定义抽象化类(图形抽象类)
核心是持有「颜色」对象的指针(桥接的关键),定义图形的通用接口:
cpp
// 抽象化(Abstraction):图形抽象类
class Shape {
protected:
Color* color; // 持有实现化对象的指针(桥接核心:连接形状和颜色)
public:
// 构造函数:注入颜色对象
explicit Shape(Color* color) : color(color) {
if (color == nullptr) {
throw std::invalid_argument("Color pointer cannot be null!");
}
}
// 纯虚函数:绘制图形(由子类实现)
virtual void draw() const = 0;
// 虚析构函数:释放颜色对象
virtual ~Shape() {
delete color;
color = nullptr;
}
// 禁用拷贝构造和赋值(避免浅拷贝导致重复释放)
Shape(const Shape&) = delete;
Shape& operator=(const Shape&) = delete;
// 移动构造和赋值(可选,提升性能)
Shape(Shape&& other) noexcept : color(other.color) {
other.color = nullptr;
}
Shape& operator=(Shape&& other) noexcept {
if (this != &other) {
delete color;
color = other.color;
other.color = nullptr;
}
return *this;
}
};
步骤 4:实现扩展抽象化类(具体图形)
cpp
// 扩展抽象化1:圆形
class Circle : public Shape {
private:
double radius; // 圆形半径
public:
// 构造函数:注入颜色+初始化半径
Circle(Color* color, double radius) : Shape(color), radius(radius) {
if (radius <= 0) {
throw std::invalid_argument("Radius must be positive!");
}
}
// 实现绘制逻辑
void draw() const override {
std::cout << "绘制一个" << color->getColorName()
<< "的圆形,半径:" << radius << std::endl;
}
};
// 扩展抽象化2:矩形
class Rectangle : public Shape {
private:
double width; // 矩形宽度
double height; // 矩形高度
public:
// 构造函数:注入颜色+初始化宽高
Rectangle(Color* color, double width, double height)
: Shape(color), width(width), height(height) {
if (width <= 0 || height <= 0) {
throw std::invalid_argument("Width and height must be positive!");
}
}
// 实现绘制逻辑
void draw() const override {
std::cout << "绘制一个" << color->getColorName()
<< "的矩形,宽:" << width << ",高:" << height << std::endl;
}
};
步骤 5:测试代码(主函数)
cpp
int main() {
try {
// 场景1:红色圆形(半径5)
Shape* redCircle = new Circle(new Red(), 5.0);
redCircle->draw();
// 场景2:蓝色矩形(宽10,高8)
Shape* blueRect = new Rectangle(new Blue(), 10.0, 8.0);
blueRect->draw();
// 扩展演示:新增绿色(只需加Green类)、三角形(只需加Triangle类)
// Shape* greenTriangle = new Triangle(new Green(), 6.0);
// greenTriangle->draw();
// 释放资源
delete redCircle;
delete blueRect;
// delete greenTriangle;
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
return 0;
}
输出结果
cpp
绘制一个红色的圆形,半径:5
绘制一个蓝色的矩形,宽:10,高:8
代码关键解释
- 桥接核心 :
Shape类中持有Color*指针,这是「桥」------ 形状(抽象维度)通过该指针调用颜色(实现维度)的方法,两者解耦; - 资源管理 :C++ 中需手动管理内存,因此在
Shape的析构函数中释放color指针,同时禁用拷贝构造 / 赋值(避免浅拷贝导致重复释放),可选实现移动语义; - 异常处理:对空指针、非法参数(如负半径)做校验,符合 C++ 健壮性要求;
- 扩展能力 :新增「绿色」只需继承
Color,新增「三角形」只需继承Shape,原有代码无需修改,符合「开闭原则」。
总结
- 桥接模式的核心是用组合(对象引用 / 指针)代替继承,分离「抽象维度」和「实现维度」,解决多层继承的类爆炸问题;
- C++ 实现中,「实现化」通常定义为纯虚类,「抽象化」持有其指针,通过构造函数注入具体实现对象,同时需注意内存管理(析构、禁用浅拷贝);
- 适用场景:当类有两个及以上独立变化的维度(如形状 + 颜色、品牌 + 功能),且需要灵活扩展时优先使用桥接模式。