设计模式之桥接模式

1 核心定义

桥接模式是一种结构型设计模式,它将抽象部分与实现部分分离,使它们都可以独立地变化。通过使用组合关系代替继承关系,桥接模式可以减少子类的数量,并避免多层继承带来的复杂性

2 核心思想

分离抽象与实现:将抽象(接口)和实现(具体实现)解耦

组合优于继承:通过对象组合建立抽象和实现之间的关系

独立变化维度:抽象和实现可以独立扩展,互不影响

多维度变化:处理多个变化维度而不导致类爆炸

3 结构组成

Abstraction(抽象类):定义抽象接口,维护对实现对象的引用

RefinedAbstraction(扩充抽象类):扩展抽象类定义的接口

Implementor(实现者接口):定义实现类的接口

ConcreteImplementor(具体实现者):实现实现者接口的具体类

4 应用场景举例

以跨平台消息发送系统为例:

消息类型:普通消息、加急消息、特急消息

发送方式:邮件发送、短信发送、微信发送

需要支持不同消息类型与不同发送方式的任意组合

5 UML

6 c++ 实现

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

// 实现类接口:消息发送方式
class MessageSender {
public:
    virtual ~MessageSender() = default;
    virtual void send(const string& message, const string& recipient) = 0;
};

// 具体实现类:邮件发送
class EmailSender : public MessageSender {
public:
    void send(const string& message, const string& recipient) override {
        cout << "发送邮件给 [" << recipient << "]: " << message << endl;
        cout << "邮件发送成功!" << endl;
    }
};

// 具体实现类:短信发送
class SmsSender : public MessageSender {
public:
    void send(const string& message, const string& recipient) override {
        cout << "发送短信给 [" << recipient << "]: " << message << endl;
        cout << "短信发送成功!" << endl;
    }
};

// 具体实现类:微信发送
class WeChatSender : public MessageSender {
public:
    void send(const string& message, const string& recipient) override {
        cout << "发送微信给 [" << recipient << "]: " << message << endl;
        cout << "微信发送成功!" << endl;
    }
};

// 抽象类:消息类型
class Message {
protected:
    MessageSender* sender;  // 桥接到发送方式
    
public:
    Message(MessageSender* s) : sender(s) {}
    virtual ~Message() {
        delete sender;
    }
    
    virtual void sendMessage(const string& message, const string& recipient) = 0;
};

// 扩展抽象类:普通消息
class NormalMessage : public Message {
public:
    NormalMessage(MessageSender* s) : Message(s) {}
    
    void sendMessage(const string& message, const string& recipient) override {
        cout << "[普通消息] ";
        sender->send(message, recipient);
    }
};

// 扩展抽象类:加急消息
class UrgentMessage : public Message {
public:
    UrgentMessage(MessageSender* s) : Message(s) {}
    
    void sendMessage(const string& message, const string& recipient) override {
        cout << "[加急消息] 请立即处理!" << endl;
        sender->send("【加急】" + message, recipient);
    }
};

// 扩展抽象类:特急消息
class VeryUrgentMessage : public Message {
public:
    VeryUrgentMessage(MessageSender* s) : Message(s) {}
    
    void sendMessage(const string& message, const string& recipient) override {
        cout << "[特急消息] 火速处理!!!" << endl;
        cout << "系统将每隔5分钟提醒一次" << endl;
        sender->send("【特急】" + message, recipient);
    }
};

// 客户端代码
int main() {
    // 创建各种组合
    cout << "=== 测试用例1:普通邮件 ===" << endl;
    Message* m1 = new NormalMessage(new EmailSender());
    m1->sendMessage("Hello World", "user@example.com");
    cout << endl;
    
    cout << "=== 测试用例2:加急短信 ===" << endl;
    Message* m2 = new UrgentMessage(new SmsSender());
    m2->sendMessage("验证码:123456", "13800138000");
    cout << endl;
    
    cout << "=== 测试用例3:特急微信 ===" << endl;
    Message* m3 = new VeryUrgentMessage(new WeChatSender());
    m3->sendMessage("系统故障,请立即处理", "管理员");
    cout << endl;
    
    // 清理内存
    delete m1;
    delete m2;
    delete m3;
    
    return 0;
}

7 总结

不使用桥接模式的坏处

如果不使用桥接模式,通常会用继承的方式实现:

方式1:使用多层继承

cpp 复制代码
// 问题:类的数量爆炸
class Message { /* ... */ };
class EmailMessage : public Message { /* ... */ };
class SmsMessage : public Message { /* ... */ };
class WeChatMessage : public Message { /* ... */ };
class UrgentEmailMessage : public EmailMessage { /* ... */ };
class UrgentSmsMessage : public SmsMessage { /* ... */ };
class UrgentWeChatMessage : public WeChatMessage { /* ... */ };
class VeryUrgentEmailMessage : public UrgentEmailMessage { /* ... */ };
// ... 如果有3种消息类型和3种发送方式,就需要3*3=9个类

方式2:使用条件判断

cpp 复制代码
class Message {
private:
    string type;      // 消息类型
    string sendWay;   // 发送方式
    
public:
    void sendMessage(const string& msg, const string& recipient) {
        // 复杂的条件判断
        if (type == "normal" && sendWay == "email") {
            // 发送普通邮件
        } else if (type == "normal" && sendWay == "sms") {
            // 发送普通短信
        } else if (type == "urgent" && sendWay == "email") {
            // 发送加急邮件
        }
        // ... 需要为每种组合编写逻辑
    }
};

主要问题:

1 类爆炸:每增加一种消息类型或发送方式,类的数量会呈乘积增长

2 代码重复:不同类型的相同发送方式,会有大量重复代码

3 维护困难:修改某一发送方式的逻辑,需要修改所有相关子类

4 违反开闭原则:添加新的组合必须修改现有代码

5 静态绑定:组合关系在编译时就确定,无法在运行时改变

桥接模式的优势

1 分离抽象和实现:两个维度可以独立变化,互不影响

2 扩展性强:添加新的消息类型或发送方式都很简单

3 符合开闭原则:扩展时不需要修改现有代码

4 减少类数量:如果有M个抽象和N个实现,只需要M+N个类,而不是M*N个

5 运行时绑定:可以在运行时动态选择实现方式

8 适用场景

1 需要在抽象和实现之间增加更多的灵活性

2 一个类存在两个独立变化的维度

3 不希望使用继承导致类爆炸

4 需要在运行时切换不同的实现

桥接模式通过将继承关系改为组合关系,很好地解决了多维变化带来的复杂性问题,是设计模式中体现"优先使用对象组合而不是继承"原则的典型例子。

相关推荐
大数据新鸟1 天前
设计模式详解——观察者模式
观察者模式·设计模式
武藤一雄1 天前
C# 设计模式大全(第一弹|7种)
microsoft·设计模式·微软·c#·.net·.netcore
Aloha_up1 天前
常见设计模式简介
设计模式
砍光二叉树1 天前
【设计模式】行为型-迭代器模式
设计模式·迭代器模式
Elaine3361 天前
【Agent 设计模式全景图:从 ReAct 到工业级多智能体架构】
设计模式·llm·软件架构·ai agent
han_1 天前
JavaScript设计模式(六):职责链模式实现与应用
前端·javascript·设计模式
无籽西瓜a1 天前
【西瓜带你学设计模式 | 第三期-工厂方法模式】工厂方法模式——定义、实现方式、优缺点与适用场景以及注意事项
java·后端·设计模式·工厂方法模式
无籽西瓜a1 天前
【西瓜带你学设计模式 | 第四期 - 抽象工厂模式】抽象工厂模式 —— 定义、核心结构、实战示例、优缺点与适用场景及模式区别
java·后端·设计模式·软件工程·抽象工厂模式
￰meteor1 天前
23种设计模式 -【抽象工厂】
后端·设计模式
程序员小寒1 天前
JavaScript设计模式(五):装饰者模式实现与应用
前端·javascript·设计模式