一、什么是桥接模式
桥接模式是一种结构型设计模式 ,它将抽象部分 与实现部分分离,使它们可以独立变化。通过组合的方式代替继承,避免了类爆炸的问题。
核心思想
将一个大类或一系列紧密相关的类拆分为抽象和实现两个独立的层次结构,通过桥接连接它们。
二、为什么要用桥接模式
常见问题场景
假设你要开发一个图形绘制系统,需要支持不同形状(圆形、方形)和不同颜色(红色、蓝色)。
使用继承的方式:
- 形状基类
- 红色圆形
- 蓝色圆形
- 绿色圆形
- 红色方形
- 蓝色方形
- 绿色方形
- ... (3种颜色 × 3种形状 = 9个类)
如果有 M 种形状和 N 种颜色,需要创建 M×N 个类,这就是类爆炸。
使用桥接模式:
- 形状独立变化
- 颜色独立变化
- 通过桥接组合,只需 M + N 个类
三、桥接模式的结构
持有引用
继承
实现
实现
Abstraction
- imp: Implementor
- operation()
RefinedAbstraction - operation()
<<interface>>
Implementor - operationImpl()
ConcreteImplA - operationImpl()
ConcreteImplB - operationImpl()
角色说明:
| 角色 | 英文名 | 定义 | 在本示例中的体现 |
|---|---|---|---|
| 抽象类 | Abstraction | 定义抽象接口,维护一个指向实现部分的引用 | Shape (形状抽象类) |
| 扩展抽象类 | RefinedAbstraction | 扩展或修改抽象类的接口定义 | Circle、Rectangle、Triangle (具体形状类) |
| 实现接口 | Implementor | 定义实现部分的接口,通常只提供基本操作 | Color (颜色接口类) |
| 具体实现类 | ConcreteImplA / ConcreteImplB | 实现Implementor接口的具体类 | Red、Blue、Green (具体颜色类) |
四、应用场景
1. 跨平台UI框架
- 抽象:窗口、按钮、文本框
- 实现:Windows、macOS、Linux的绘制API
2. 数据库驱动
- 抽象:数据库操作(增删改查)
- 实现:MySQL、PostgreSQL、Oracle的具体实现
3. 消息发送系统
- 抽象:消息类型(普通、加急、定时)
- 实现:发送方式(邮件、短信、微信)
4. 图形系统
- 抽象:形状(圆形、矩形、三角形)
- 实现:渲染引擎(OpenGL、DirectX、Vulkan)
5. 设备控制系统
- 抽象:遥控器(开关、调音量)
- 实现:设备(电视、音响、投影仪)
五、C++代码示例
示例1:图形绘制系统
cpp
#include <iostream>
#include <memory>
#include <string>
// 前向声明
class Color;
// ========== 实现部分:颜色接口 ==========
class Color {
public:
virtual ~Color() = default;
virtual void applyColor() const = 0;
};
// 具体实现:红色
class Red : public Color {
public:
void applyColor() const override {
std::cout << "应用红色" << std::endl;
}
};
// 具体实现:蓝色
class Blue : public Color {
public:
void applyColor() const override {
std::cout << "应用蓝色" << std::endl;
}
};
// 具体实现:绿色
class Green : public Color {
public:
void applyColor() const override {
std::cout << "应用绿色" << std::endl;
}
};
// ========== 抽象部分:形状 ==========
class Shape {
protected:
std::shared_ptr<Color> color_; // 桥接:持有颜色对象的引用
public:
Shape(std::shared_ptr<Color> color) : color_(color) {}
virtual ~Shape() = default;
virtual void draw() const = 0;
};
// 扩展抽象:圆形
class Circle : public Shape {
private:
double radius_;
public:
Circle(std::shared_ptr<Color> color, double radius)
: Shape(color), radius_(radius) {}
void draw() const override {
std::cout << "绘制半径为 " << radius_ << " 的圆形,";
color_->applyColor();
}
};
// 扩展抽象:矩形
class Rectangle : public Shape {
private:
double width_, height_;
public:
Rectangle(std::shared_ptr<Color> color, double width, double height)
: Shape(color), width_(width), height_(height) {}
void draw() const override {
std::cout << "绘制尺寸为 " << width_ << "x" << height_ << " 的矩形,";
color_->applyColor();
}
};
// 扩展抽象:三角形
class Triangle : public Shape {
private:
double sideLength_;
public:
Triangle(std::shared_ptr<Color> color, double sideLength)
: Shape(color), sideLength_(sideLength) {}
void draw() const override {
std::cout << "绘制边长为 " << sideLength_ << " 的三角形,";
color_->applyColor();
}
};
// 使用示例
int main() {
// 创建颜色对象
auto red = std::make_shared<Red>();
auto blue = std::make_shared<Blue>();
auto green = std::make_shared<Green>();
// 创建各种形状,组合不同颜色
std::vector<std::shared_ptr<Shape>> shapes;
shapes.push_back(std::make_shared<Circle>(red, 5.0));
shapes.push_back(std::make_shared<Rectangle>(blue, 10.0, 20.0));
shapes.push_back(std::make_shared<Triangle>(green, 8.0));
shapes.push_back(std::make_shared<Circle>(green, 3.0));
// 绘制所有形状
for (const auto& shape : shapes) {
shape->draw();
}
return 0;
}
示例2:消息发送系统
cpp
#include <iostream>
#include <memory>
#include <string>
#include <chrono>
#include <thread>
// ========== 实现部分:消息发送方式 ==========
class MessageSender {
public:
virtual ~MessageSender() = default;
virtual void send(const std::string& message) const = 0;
};
// 邮件发送
class EmailSender : public MessageSender {
private:
std::string email_;
public:
EmailSender(const std::string& email) : email_(email) {}
void send(const std::string& message) const override {
std::cout << "发送邮件到 " << email_ << ": " << message << std::endl;
}
};
// 短信发送
class SMSSender : public MessageSender {
private:
std::string phoneNumber_;
public:
SMSSender(const std::string& phone) : phoneNumber_(phone) {}
void send(const std::string& message) const override {
std::cout << "发送短信到 " << phoneNumber_ << ": " << message << std::endl;
}
};
// 微信发送
class WeChatSender : public MessageSender {
private:
std::string wechatId_;
public:
WeChatSender(const std::string& id) : wechatId_(id) {}
void send(const std::string& message) const override {
std::cout << "发送微信到 " << wechatId_ << ": " << message << std::endl;
}
};
// ========== 抽象部分:消息 ==========
class Message {
protected:
std::shared_ptr<MessageSender> sender_;
public:
Message(std::shared_ptr<MessageSender> sender) : sender_(sender) {}
virtual ~Message() = default;
virtual void deliver(const std::string& content) const = 0;
};
// 普通消息
class NormalMessage : public Message {
public:
NormalMessage(std::shared_ptr<MessageSender> sender) : Message(sender) {}
void deliver(const std::string& content) const override {
std::cout << "[普通消息] ";
sender_->send(content);
}
};
// 加急消息
class UrgentMessage : public Message {
public:
UrgentMessage(std::shared_ptr<MessageSender> sender) : Message(sender) {}
void deliver(const std::string& content) const override {
std::cout << "[加急消息] ";
sender_->send("[URGENT] " + content);
}
};
// 定时消息
class ScheduledMessage : public Message {
private:
int delaySeconds_;
public:
ScheduledMessage(std::shared_ptr<MessageSender> sender, int delay)
: Message(sender), delaySeconds_(delay) {}
void deliver(const std::string& content) const override {
std::cout << "[定时消息] 将在 " << delaySeconds_ << " 秒后发送" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(delaySeconds_));
sender_->send(content);
}
};
// 使用示例
int main() {
// 创建发送方式
auto emailSender = std::make_shared<EmailSender>("user@example.com");
auto smsSender = std::make_shared<SMSSender>("13800138000");
auto wechatSender = std::make_shared<WeChatSender>("wxid_123456");
// 创建各种消息,组合不同发送方式
auto normalEmail = NormalMessage(emailSender);
auto urgentSMS = UrgentMessage(smsSender);
auto scheduledWeChat = ScheduledMessage(wechatSender, 2);
// 发送消息
normalEmail.deliver("会议提醒");
urgentSMS.deliver("服务器宕机!");
scheduledWeChat.deliver("明天记得开会");
return 0;
}
六、桥接模式 vs 其他模式
| 模式 | 区别 |
|---|---|
| 适配器模式 | 适配器用于让不兼容的接口协同工作(事后调整);桥接用于设计时就分离抽象和实现(事前设计) |
| 策略模式 | 策略模式关注算法的切换;桥接模式关注抽象和实现的分离,更强调两个维度的独立变化 |
| 模板方法模式 | 模板方法使用继承;桥接使用组合,更灵活 |
七、优缺点
优点
- ✅ 单一职责原则:抽象和实现分离,各自独立变化
- ✅ 开闭原则:可以独立扩展抽象和实现层次,不影响对方
- ✅ 消除类爆炸:避免M×N的类组合爆炸
- ✅ 提高可扩展性:增加新的实现或抽象都很方便
- ✅ 实现细节隐藏:客户端不需要关心具体实现细节
缺点
- ❌ 增加复杂度:需要理解"抽象-实现"分离的概念
- ❌ 可能过度设计:对于简单的继承体系不适用
- ❌ 需要准确识别变化维度:需要正确识别系统中独立变化的两个维度
八、使用建议
何时使用桥接模式?
- ✅ 想要避免抽象和实现之间的永久绑定
- ✅ 抽象和实现都应该是可扩展的
- ✅ 对客户隐藏实现细节
- ✅ 有多个独立的维度需要变化
- ✅ 需要在运行时切换实现
何时避免使用?
- ❌ 只有一个实现维度时,没必要使用
- ❌ 抽象和实现的关系不会变化
- ❌ 系统已经很简单,使用桥接反而增加复杂度
总结
桥接模式通过将继承关系转化为组合关系,成功解决了多维度变化导致的类爆炸问题。它让抽象和实现可以独立发展,是应对复杂系统扩展的优秀设计模式。在实际开发中,当你发现类爆炸的苗头或者需要支持多个独立变化的维度时,就可以考虑使用桥接模式。