桥接模式的意图和动机
桥接模式的意图是将抽象部分与它的实现部分分离,使它们可以独立地变化。这意味着你可以独立地修改或扩展抽象部分和实现部分,而不会相互影响。桥接模式的主要动机是通过这种分离来增强系统的灵活性和可扩展性。
桥接模式适用于解决什么问题
桥接模式适用于以下场景:
-
多维度变化:当一个系统需要在多个维度上进行扩展时,桥接模式可以避免类爆炸问题。例如,一个图形绘制系统中,图形可以是圆形、矩形等,而颜色可以是红色、蓝色等。如果为每种图形和颜色的组合创建一个类,将会导致类的数量急剧增加。
-
抽象与实现的分离:当需要分离抽象和实现,使得它们可以独立变化时,桥接模式是一个合适的选择。
-
避免永久绑定:当需要在运行时动态地切换实现时,桥接模式允许抽象和实现可以独立变化,从而避免永久绑定。
桥接模式的适用场合
桥接模式特别适用于以下场合:
- 系统需要在多个独立维度上扩展:例如,图形和颜色可以独立变化。
- 需要在运行时切换实现:例如,用户可以根据需要选择不同的图形库或颜色方案。
- 避免类爆炸:通过分离抽象和实现,避免创建大量的子类。
桥接模式的结构和参与角色
桥接模式的结构包括以下几个核心角色:
- Abstraction(抽象类):定义抽象部分的接口,并维护一个指向
Implementor
类型对象的引用。 - RefinedAbstraction(扩充抽象类):扩充由
Abstraction
定义的接口。 - Implementor(实现类接口):定义实现部分的接口,这个接口不必与
Abstraction
的接口完全一致。通常情况下,Implementor
接口只提供基本操作,而Abstraction
定义了基于这些基本操作的更高层次的操作。 - ConcreteImplementor(具体实现类):实现
Implementor
接口并定义具体实现。
桥接模式的UML类图
+-----------------+ +-----------------+
| Abstraction | | Implementor |
|-----------------| |-----------------|
| + operation() |<---------| + operationImp()|
+-----------------+ +-----------------+
| |
| |
v v
+-----------------+ +-----------------+
| RefinedAbstraction | | ConcreteImplementor|
|-----------------| |-----------------|
| + operation() | | + operationImp()|
+-----------------+ +-----------------+
解释
- Abstraction:定义抽象部分的接口,并维护一个指向
Implementor
的引用。 - RefinedAbstraction:扩展
Abstraction
的接口,提供更丰富的操作。 - Implementor:定义实现部分的接口。
- ConcreteImplementor:实现
Implementor
接口,提供具体的实现。
通过这种结构,桥接模式允许抽象和实现可以独立变化,从而增强了系统的灵活性和可扩展性。
C++示例代码:
场景1:多维度变化(如图形和颜色)
在图形绘制系统中,图形可以是圆形、矩形等,颜色可以是红色、蓝色等。通过桥接模式,我们可以独立地扩展图形和颜色。
#include <iostream>
// Implementor: 颜色接口
class Color {
public:
virtual void applyColor() = 0;
};
// ConcreteImplementor: 红色
class RedColor : public Color {
public:
void applyColor() override {
std::cout << "Applying red color" << std::endl;
}
};
// ConcreteImplementor: 蓝色
class BlueColor : public Color {
public:
void applyColor() override {
std::cout << "Applying blue color" << std::endl;
}
};
// Abstraction: 抽象图形
class Shape {
protected:
Color* color;
public:
Shape(Color* c) : color(c) {}
virtual void draw() = 0;
};
// RefinedAbstraction: 圆形
class Circle : public Shape {
public:
Circle(Color* c) : Shape(c) {}
void draw() override {
std::cout << "Drawing Circle. ";
color->applyColor();
}
};
// RefinedAbstraction: 矩形
class Rectangle : public Shape {
public:
Rectangle(Color* c) : Shape(c) {}
void draw() override {
std::cout << "Drawing Rectangle. ";
color->applyColor();
}
};
int main() {
// 创建颜色
Color* red = new RedColor();
Color* blue = new BlueColor();
// 创建图形并应用颜色
Shape* redCircle = new Circle(red);
Shape* blueRectangle = new Rectangle(blue);
// 绘制图形
redCircle->draw();
blueRectangle->draw();
// 清理资源
delete red;
delete blue;
delete redCircle;
delete blueRectangle;
return 0;
}
场景2:需要在运行时切换实现
假设我们有一个消息发送系统,消息可以通过短信或电子邮件发送。我们可以通过桥接模式在运行时切换发送方式。
#include <iostream>
// Implementor: 消息发送接口
class MessageSender {
public:
virtual void sendMessage(const std::string& message) = 0;
};
// ConcreteImplementor: 短信发送
class SMSSender : public MessageSender {
public:
void sendMessage(const std::string& message) override {
std::cout << "Sending SMS: " << message << std::endl;
}
};
// ConcreteImplementor: 电子邮件发送
class EmailSender : public MessageSender {
public:
void sendMessage(const std::string& message) override {
std::cout << "Sending Email: " << message << std::endl;
}
};
// Abstraction: 消息
class Message {
protected:
MessageSender* sender;
public:
Message(MessageSender* s) : sender(s) {}
virtual void send(const std::string& message) = 0;
};
// RefinedAbstraction: 普通消息
class TextMessage : public Message {
public:
TextMessage(MessageSender* s) : Message(s) {}
void send(const std::string& message) override {
sender->sendMessage(message);
}
};
int main() {
// 创建发送方式
MessageSender* smsSender = new SMSSender();
MessageSender* emailSender = new EmailSender();
// 创建消息并选择发送方式
Message* smsMessage = new TextMessage(smsSender);
Message* emailMessage = new TextMessage(emailSender);
// 发送消息
smsMessage->send("Hello via SMS");
emailMessage->send("Hello via Email");
// 清理资源
delete smsSender;
delete emailSender;
delete smsMessage;
delete emailMessage;
return 0;
}
场景3:避免类爆炸
假设我们有一个设备控制系统,设备可以是电视或空调,控制方式可以是遥控器或手机App。通过桥接模式,我们可以避免为每种设备和控制方式的组合创建大量的子类。
#include <iostream>
// Implementor: 设备控制接口
class DeviceControl {
public:
virtual void turnOn() = 0;
virtual void turnOff() = 0;
};
// ConcreteImplementor: 电视控制
class TVControl : public DeviceControl {
public:
void turnOn() override {
std::cout << "Turning on TV" << std::endl;
}
void turnOff() override {
std::cout << "Turning off TV" << std::endl;
}
};
// ConcreteImplementor: 空调控制
class ACControl : public DeviceControl {
public:
void turnOn() override {
std::cout << "Turning on Air Conditioner" << std::endl;
}
void turnOff() override {
std::cout << "Turning off Air Conditioner" << std::endl;
}
};
// Abstraction: 控制器
class Controller {
protected:
DeviceControl* device;
public:
Controller(DeviceControl* d) : device(d) {}
virtual void on() = 0;
virtual void off() = 0;
};
// RefinedAbstraction: 遥控器
class RemoteController : public Controller {
public:
RemoteController(DeviceControl* d) : Controller(d) {}
void on() override {
std::cout << "Using Remote to turn on: ";
device->turnOn();
}
void off() override {
std::cout << "Using Remote to turn off: ";
device->turnOff();
}
};
// RefinedAbstraction: 手机App
class AppController : public Controller {
public:
AppController(DeviceControl* d) : Controller(d) {}
void on() override {
std::cout << "Using App to turn on: ";
device->turnOn();
}
void off() override {
std::cout << "Using App to turn off: ";
device->turnOff();
}
};
int main() {
// 创建设备
DeviceControl* tv = new TVControl();
DeviceControl* ac = new ACControl();
// 创建控制器并选择设备
Controller* remoteControlTV = new RemoteController(tv);
Controller* appControlAC = new AppController(ac);
// 使用遥控器控制电视
remoteControlTV->on();
remoteControlTV->off();
// 使用手机App控制空调
appControlAC->on();
appControlAC->off();
// 清理资源
delete tv;
delete ac;
delete remoteControlTV;
delete appControlAC;
return 0;
}
代码说明
- DeviceControl:设备控制接口,定义了
turnOn
和turnOff
方法。 - TVControl 和 ACControl:具体的设备实现类,分别实现电视和空调的开关操作。
- Controller:控制器抽象类,包含一个
DeviceControl
对象,并定义了on
和off
方法。 - RemoteController 和 AppController:具体的控制器实现类,分别实现遥控器和手机App的控制逻辑。
- main 函数:演示如何使用桥接模式来避免类爆炸问题,通过组合不同的设备和控制器来实现灵活的控制。
通过这种方式,我们可以灵活地组合不同的设备和控制器,而不需要为每种组合创建大量的子类。