5.桥模式(Bridge)
动机
由于某些类型的固有的实现逻辑,使得它们具有两个变化的维度,乃至多个纬度的变化。
class Messager{
public:
// 登录
virtual void Login(string username, string password)=0;
// 发送消息
virtual void SendMessage(string message)=0;
// 发送图片
virtual void SendPicture(Image image)=0;
// 播放声音
virtual void PlaySound()=0;
// 绘制图形
virtual void DrawShape()=0;
// 写入文本
virtual void WriteText()=0;
// 链接
virtual void Connect()=0;
virtual ~Messager(){}
};
//平台实现
// PC端
class PCMessagerBase : public Messager{
public:
virtual void PlaySound(){
//**********
}
virtual void DrawShape(){
//**********
}
virtual void WriteText(){
//**********
}
virtual void Connect(){
//**********
}
};
// 移动端
class MobileMessagerBase : public Messager{
public:
virtual void PlaySound(){
//==========
}
virtual void DrawShape(){
//==========
}
virtual void WriteText(){
//==========
}
virtual void Connect(){
//==========
}
};
//业务抽象
class PCMessagerLite : public PCMessagerBase {
public:
virtual void Login(string username, string password){
PCMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
PCMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
PCMessagerBase::DrawShape();
//........
}
};
class PCMessagerPerfect : public PCMessagerBase {
public:
virtual void Login(string username, string password){
PCMessagerBase::PlaySound();
//********
PCMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
PCMessagerBase::PlaySound();
//********
PCMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
PCMessagerBase::PlaySound();
//********
PCMessagerBase::DrawShape();
//........
}
};
class MobileMessagerLite : public MobileMessagerBase {
public:
virtual void Login(string username, string password){
MobileMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
MobileMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
MobileMessagerBase::DrawShape();
//........
}
};
class MobileMessagerPerfect : public MobileMessagerBase {
public:
virtual void Login(string username, string password){
MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::DrawShape();
//........
}
};
void Process(){
//编译时装配
Messager *m =
new MobileMessagerPerfect();
}
说明:
基类 (Messager) :
定义了消息应用的核心功能接口,包括登录、发送消息、发送图片、播放声音、绘制图形、书写文本和连接等
平台实现类:
PCMessagerBase 是 PC端的底层实现。
MobileMessagerBase 是 移动端的底层实现。
业务抽象类
PCMessagerLite 和 PCMessagerPerfect 是PC端业务。
MobileMessagerLite 和 MobileMessagerPerfect 是移动端业务。
存在问题:
- 基类 (Messager) 承载了太多职责,导致类的复杂程度变高,难以维护和拓展。我们需要将这些功能拆分到不同的类中,每个类只负责一个明确职责。
- 业务抽象类这部分 PC 实现和 安卓实现几乎相同,只是调用基类方法不同。这种重复只会增加维护成本。
- 继承结构过深,这种深度继承会导致类之间的关系复杂,难以理解和扩展。更好的方式是使用组合而非继承,将平台实现和功能实现分离。
- 缺乏可持续性,当前的设计将平台和功能绑定在一起(例如 PCMessagerLite 和 MobileMessagerLite),如果需要增加新的平台或功能,会导致类的数量急剧增加
修改后:
// 平台接口
class Platform {
public:
virtual void PlaySound() = 0;
virtual void DrawShape() = 0;
virtual void WriteText() = 0;
virtual void Connect() = 0;
virtual ~Platform() {}
};
// PC端实现
class PCPlatform : public Platform {
public:
void PlaySound() override {
// PC端播放音效的实现
}
void DrawShape() override {
// PC端绘制图形的实现
}
void WriteText() override {
// PC端书写文本的实现
}
void Connect() override {
// PC端连接的实现
}
};
// 移动端实现
class MobilePlatform : public Platform {
public:
void PlaySound() override {
// 移动端播放音效的实现
}
void DrawShape() override {
// 移动端绘制图形的实现
}
void WriteText() override {
// 移动端书写文本的实现
}
void Connect() override {
// 移动端连接的实现
}
};
// 功能抽象
class Messager {
protected:
Platform* platform; // 组合平台对象
public:
Messager(Platform* platform) : platform(platform) {}
virtual void Login(string username, string password) = 0;
virtual void SendMessage(string message) = 0;
virtual void SendPicture(Image image) = 0;
virtual ~Messager() {}
};
// 精简版功能
class MessagerLite : public Messager {
public:
MessagerLite(Platform* platform) : Messager(platform) {}
void Login(string username, string password) override {
platform->Connect();
// 其他登录逻辑
}
void SendMessage(string message) override {
platform->WriteText();
// 其他消息发送逻辑
}
void SendPicture(Image image) override {
platform->DrawShape();
// 其他图片发送逻辑
}
};
// 完整版功能
class MessagerPerfect : public Messager {
public:
MessagerPerfect(Platform* platform) : Messager(platform) {}
void Login(string username, string password) override {
platform->PlaySound();
platform->Connect();
// 其他登录逻辑
}
void SendMessage(string message) override {
platform->PlaySound();
platform->WriteText();
// 其他消息发送逻辑
}
void SendPicture(Image image) override {
platform->PlaySound();
platform->DrawShape();
// 其他图片发送逻辑
}
};
// 使用示例
void Process() {
Platform* pcPlatform = new PCPlatform();
Platform* mobilePlatform = new MobilePlatform();
Messager* pcMessagerLite = new MessagerLite(pcPlatform);
Messager* mobileMessagerPerfect = new MessagerPerfect(mobilePlatform);
// 使用对象
pcMessagerLite->Login("user", "password");
mobileMessagerPerfect->SendMessage("Hello, World!");
// 释放资源
delete pcMessagerLite;
delete mobileMessagerPerfect;
delete pcPlatform;
delete mobilePlatform;
}
改进后优点:
- 职责清晰:每个类只负责一个明确的职责,符合单一职责原则。
- 代码复用:通过组合模式,减少了代码重复。
- 灵活扩展:可以轻松增加新的平台或功能,而不需要修改现有代码。
- 易于维护:类的层次结构更简单,易于理解和维护。
总结
Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自纬度的变化,即“子类化”它们。
Bridge模式有时候类似于多继承方案,但是多继承方案往往违背单一职责原则(即一个类只有一个变化的原因),复用性比较差。Bridge模式是比多继承方案更好的解决方法。
Bridge模式的应用一般在“两个非常强的变化维度”,有时一个类也有多于两个的变化维度,这时可以使用Bridge的扩展模式。