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

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

一、什么是桥接模式?

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

举个直观的例子:如果有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. 多维度扩展:如果遥控器还需要支持"红外"和"蓝牙"两种连接方式,可再增加"连接方式"维度,通过桥接模式继续扩展,依然保持低耦合。

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

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

相关推荐
blasit11 小时前
笔记:Qt C++建立子线程做一个socket TCP常连接通信
c++·qt·tcp/ip
七月丶16 小时前
别再手动凑 PR 了:这个 AI Skill 会按仓库习惯自动建分支、拆提交、提 PR
人工智能·设计模式·程序员
刀法如飞16 小时前
从程序员到架构师:6大编程范式全解析与实践对比
设计模式·系统架构·编程范式
九狼17 小时前
Flutter + Riverpod +MVI 架构下的现代状态管理
设计模式
静水流深_沧海一粟1 天前
04 | 别再写几十个参数的构造函数了——建造者模式
设计模式
StarkCoder1 天前
从UIKit到SwiftUI的迁移感悟:数据驱动的革命
设计模式
肆忆_2 天前
# 用 5 个问题学懂 C++ 虚函数(入门级)
c++
不想写代码的星星2 天前
虚函数表:C++ 多态背后的那个男人
c++
阿星AI工作室2 天前
给openclaw龙虾造了间像素办公室!实时看它写代码、摸鱼、修bug、写日报,太可爱了吧!
前端·人工智能·设计模式
_哆啦A梦3 天前
Vibe Coding 全栈专业名词清单|设计模式·基础篇(创建型+结构型核心名词)
前端·设计模式·vibecoding