桥接模式实战:用万能遥控器控制多品牌电视

桥接模式实战:用万能遥控器控制多品牌电视

一、什么是桥接模式?

桥接模式的核心思想是"将抽象部分与实现部分分离,使它们都可以独立地变化"。简单来说,当一个系统需要从两个或多个维度进行扩展时,桥接模式通过"组合"而非"继承"的方式,将这些维度连接起来,避免因维度组合产生的"类爆炸"问题。

举个直观的例子:如果有2个电视品牌(Sony、TCL)和3种操作(开机、关机、换台),用传统继承的方式需要创建2×3=6个类;如果再增加1个品牌和1种操作,需要新增3+2=5个类。而用桥接模式,新增1个品牌只需加1个类,新增1种操作也只需加1个类------这就是桥接模式的核心价值:让每个维度可以独立扩展,彼此不受影响,降低耦合性。

二、案例场景:小明的万能遥控器

小明新家有两台电视:一台Sony客厅电视,一台TCL卧室电视。他买了一个"万能遥控器",有三个按钮分别对应"开机""关机""切换频道",并且能自动适配不同品牌的电视。

这个场景中存在两个独立变化的维度:

  1. 电视品牌维度:目前有Sony、TCL,未来可能增加三星、小米等;
  2. 操作类型维度:目前有开机、关机、切换频道,未来可能增加调节音量、切换信号源等。

这正是桥接模式的典型应用场景------通过"遥控器"这个"桥",将"操作"和"电视品牌"两个维度连接起来,实现灵活组合。

三、桥接模式的UML图

通用桥接模式UML图

桥接模式包含4个核心角色,其通用结构如下:

角色说明:

  1. Abstraction(抽象化角色):定义抽象接口,持有一个Implementor对象的引用(即"桥");
  2. RefinedAbstraction(扩展抽象化角色):继承Abstraction,扩展其功能;
  3. Implementor(实现化角色):定义实现类的接口,供Abstraction调用;
  4. ConcreteImplementor(具体实现化角色):实现Implementor接口,提供具体功能。

本例的UML图

结合"万能遥控器控制电视"的场景,UML图如下:

角色映射:

  1. AbstractionRemoteControl(遥控器抽象类,持有TV引用);
  2. RefinedAbstractionPowerOperationOffOperationChannelSwitchOperation(具体操作);
  3. ImplementorTV(电视接口,定义核心操作);
  4. ConcreteImplementorSonyTVTCLTV(具体品牌电视)。

四、代码实现与解析

下面用C++实现这个场景,完整代码如下:

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>

using namespace std;

// 步骤1: 定义实现化接口(Implementor)------ TV
class TV {
public:
    virtual void turnOn() = 0;
    virtual void turnOff() = 0;
    virtual void switchChannel() = 0;
    virtual ~TV() = default;
};

// 步骤2: 实现具体实现化类(ConcreteImplementor)
class SonyTV : public TV {
public:
    void turnOn() override {
        cout << "Sony TV is ON" << endl;
    }

    void turnOff() override {
        cout << "Sony TV is OFF" << endl;
    }

    void switchChannel() override {
        cout << "Switching Sony TV channel" << endl;
    }
};

class TCLTV : public TV {
public:
    void turnOn() override {
        cout << "TCL TV is ON" << endl;
    }

    void turnOff() override {
        cout << "TCL TV is OFF" << endl;
    }

    void switchChannel() override {
        cout << "Switching TCL TV channel" << endl;
    }
};

// 步骤3: 定义抽象化角色(Abstraction)------ RemoteControl
class RemoteControl {
protected:
    TV* tv;  // 桥接TV对象

public:
    RemoteControl(TV* tv) : tv(tv) {}
    virtual void performOperation() = 0;
    virtual ~RemoteControl() = default;
};

// 步骤4: 实现扩展抽象化类(RefinedAbstraction)
class PowerOperation : public RemoteControl {
public:
    using RemoteControl::RemoteControl;

    void performOperation() override {
        tv->turnOn();
    }
};

class OffOperation : public RemoteControl {
public:
    using RemoteControl::RemoteControl;

    void performOperation() override {
        tv->turnOff();
    }
};

class ChannelSwitchOperation : public RemoteControl {
public:
    using RemoteControl::RemoteControl;

    void performOperation() override {
        tv->switchChannel();
    }
};

// 步骤5: 客户端代码(不使用sstream,手动解析输入)
int main() {
    int N;
    cin >> N;
    cin.ignore();  // 忽略换行符

    for (int i = 0; i < N; i++) {
        string input;
        getline(cin, input);
        
        // 手动解析输入中的两个整数(品牌和操作)
        int brand = 0, operation = 0;
        int pos = 0;
        // 解析品牌(第一个数字)
        while (pos < input.size() && input[pos] != ' ') {
            brand = brand * 10 + (input[pos] - '0');
            pos++;
        }
        pos++;  // 跳过空格
        // 解析操作(第二个数字)
        while (pos < input.size()) {
            operation = operation * 10 + (input[pos] - '0');
            pos++;
        }

        // 创建具体电视
        TV* tv = nullptr;
        if (brand == 0) {
            tv = new SonyTV();
        } else {
            tv = new TCLTV();
        }

        // 创建具体操作
        RemoteControl* remoteControl = nullptr;
        if (operation == 2) {
            remoteControl = new PowerOperation(tv);
        } else if (operation == 3) {
            remoteControl = new OffOperation(tv);
        } else {
            remoteControl = new ChannelSwitchOperation(tv);
        }

        // 执行操作
        remoteControl->performOperation();

        // 释放资源
        delete remoteControl;
        delete tv;
    }

    return 0;
}

代码解析:

  1. 实现化维度(TV)TV接口定义了电视的核心操作,SonyTVTCLTV分别实现了具体品牌的逻辑。未来新增品牌时,只需继承TV并实现接口,无需修改其他代码;
  2. 抽象化维度(RemoteControl)RemoteControl作为抽象遥控器,通过成员变量tv持有TV指针,形成连接两个维度的"桥"。PowerOperation等子类则实现了具体操作逻辑,新增操作时只需继承RemoteControl即可;
  3. 桥接的建立 :客户端通过将TV对象传入RemoteControl子类的构造函数,动态建立两个维度的关联,实现"操作"与"品牌"的灵活组合;
  4. 灵活性体现:当需要控制新品牌电视或新增操作时,只需扩展对应维度的类,原有代码无需修改,完全符合"开闭原则"。

五、桥接模式的优势与扩展思考

核心优势

  1. 分离抽象与实现:电视品牌和遥控器操作各自独立演化,修改一个维度不会影响另一个维度;
  2. 避免类爆炸:假设有M个品牌和N个操作,桥接模式只需M+N个类,而继承方式需要M×N个类;
  3. 高扩展性:新增品牌或操作时,只需添加对应类即可,无需修改现有代码;
  4. 职责单一:每个类只负责一个维度的逻辑,代码结构清晰,便于维护。

扩展场景思考

  1. 新增电视品牌 :比如添加"小米电视",只需创建MiTV类继承TV,实现turnOnturnOffswitchChannel方法,客户端代码无需任何修改;
  2. 新增操作 :比如添加"调节音量",只需在TV接口中增加adjustVolume方法,然后创建VolumeOperation类继承RemoteControl,在performOperation中调用tv->adjustVolume()
  3. 多维度扩展:如果遥控器还需要支持"红外"和"蓝牙"两种连接方式,可再增加"连接方式"维度,通过桥接模式继续扩展,依然保持低耦合。

桥接模式通过"组合"替代"继承",完美解决了多维度扩展的问题。在实际开发中,当系统存在多个独立变化的维度(如"产品类型"与"品牌"、"操作"与"设备")时,桥接模式能显著提升系统的灵活性和可扩展性。

本文桥接模式的核心概念参考自《大话设计模式》场景案例参考卡码网。

相关推荐
Wuliwuliii2 小时前
闵可夫斯基和、需存储的最小状态集
c++·算法·动态规划·闵可夫斯基和
驱动男孩2 小时前
c++新特性- 个人总结
c++·c++新特性
行稳方能走远2 小时前
Android C++ 学习笔记 2
android·c++
浅川.252 小时前
STL专项:deque 双端队列
开发语言·c++·stl·deque
mmz12072 小时前
差分数组(二维)(c++)
c++·算法
闻缺陷则喜何志丹3 小时前
【计算几何 化环为链】P14165 [ICPC 2022 Nanjing R] 清空水箱|普及+
c++·数学·算法·计算几何·洛谷·化环为链
爱吃生蚝的于勒3 小时前
【Linux】深入理解软硬链接
linux·运维·服务器·c语言·数据结构·c++·算法
老王熬夜敲代码3 小时前
C++模版元编程1
数据结构·c++·笔记