桥接模式(Bridge)


引言

假如有三个品牌的手机vivo,oppo和小米,如果手机手机壳一体生产,会是这样的:

对应到相应的类中,将是1+3+6=10个有继承关系的类,如果这时再加一个华为手机,无疑是要多增加3个类,会带来类的急剧增长。
如果手机手机壳分开生产,然后按需搭配,就是这样的:

对应到类设计中,只需要7个类,如果增加一类手机,只需增加一个类,增加一款手机壳,也只需增加一个类。
对应的各维度关系也可以通过下图观察:

这种处理多维变化(手机和手机壳)的方式运用到软件设计中就是桥接模式。

桥接模式的应用

何时使用

  • 系统可能有多个角度分类,每一种角度都可能变化时

方法

  • 把这种角度分类分离出来,让它们单独变化,减少它们之间的耦合(合成/聚合复用原则)

优点

  • 抽象和实现分离。桥梁模式完全是为了解决继承的缺点而提出的设计模式
  • 优秀的扩展能力
  • 实现细节对客户透明。客户不用关心细节的实现,它已经由抽象层通过聚合关系完成了封装

缺点

  • 会增加系统的理解与设计难度。由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程

使用场景

  • 不希望或不适用使用继承的场景
  • 接口或抽象类不稳定的场景
  • 重用性要求较高的场景

注意事项

  • 不要一涉及继承就考虑该模式,尽可能把变化的因素封装到最细、最小的逻辑单元中,避免风险扩散
  • 当发现类的继承有n层时,可以考虑使用该模式

结构


从UML类图中,可以看到,桥接模式主要包含4种角色:

  • 抽象(Abstraction):该类持有一个对实现角色的引用以维护该对象,抽象角色中的方法需要实现角色来实现。抽象角色一般为抽象类(构造函数规定子类要传入一个实现角色)

  • 修正抽象(RefineAbstraction): Abstraction的具体实现。对Abstraction的方法进行完善和扩展

  • 实现(Implementor):定义实现维度的基本操作,提供给Abstraction使用。该类一般为接口或抽象类

  • 具体实现(ConcreteImplementor):Implementor的具体实现

     观察UML类图中 Abstraction和Implementor连接的那条线(抽象层建立的抽象关联),就像一个桥,将两个变化维度连接起来,各个维度都可以独立的变化,这也是 桥接 的来源。<br />       可以明显看出,桥接模式使用组合代替了继承,将类之间的静态继承关系转换为动态的对象组合关系,使用组合而不用继承,会使系统更加灵活,并易于扩展,同时有效控制了系统中类的个数。
    

代码示例

   以手机和手机APP的关系为例,一个手机可以运行不同的APP,一个APP可以不同的手机上运行。将A手机作为抽象,将APP作为实现,利用桥接模式代码示例如下:<br />和之前一样,代码仍然采用智能指针.
#include <bits/stdc++.h>

//
//桥接模式
//关键代码:将实现独立出来,抽象类依赖现实类。
//以下示例中,将各类App、各类手机独立开来,实现各种App和各种手机的自由桥接/组合
//


//抽象App类,提供接口
class App {
public:
    virtual ~App() = default;

    virtual void run() = 0;
};

//具体的App实现类
class GameApp : public App {
public:
    void run() override {
        std::cout << "GameApp Running" << std::endl;
    }
};

//具体的App实现类
class TranslateApp : public App {
public:
    void run() override {
        std::cout << "TranslateApp Running" << std::endl;
    }
};

//抽象手机类,提供接口
class MobilePhone {
public:
    virtual ~MobilePhone() = default;

    //构造函数不能定义为虚函数.有兴趣的可以思考一下why.
    MobilePhone(const std::shared_ptr<App> pApp) : m_pApp(pApp) {}

    virtual void appRun() = 0;

protected:
    //由于继承类要使用该对象,因此不能定义为private类型
    std::shared_ptr<App> m_pApp;//持有一个实现的引用.类通过该对象实现app与手机的桥接
};

//具体的手机实现类
class XiaoMi : public MobilePhone {
public:
    XiaoMi(const std::shared_ptr<App> pApp) : MobilePhone(pApp) {}

    void appRun() override {
        std::cout << "XiaoMi: ";
        m_pApp->run();
    }
};

//具体的手机实现类
class HuaWei : public MobilePhone {
public:
    HuaWei(const std::shared_ptr<App> pApp) : MobilePhone(pApp) {}

    void appRun() override {
        std::cout << "HuaWei: ";
        m_pApp->run();
    }
};

int main() {
    std::shared_ptr<App> pGameApp = std::make_shared<GameApp>();//实现部分
    std::shared_ptr<MobilePhone> pXiaoMi = std::make_shared<XiaoMi>(pGameApp);//抽象部分
    pXiaoMi->appRun();

    std::shared_ptr<App> pTranslateApp = std::make_shared<TranslateApp>();//实现部分
    pXiaoMi = std::make_shared<XiaoMi>(pTranslateApp);//抽象部分
    pXiaoMi->appRun();

    std::cout << std::string(50, '-') << std::endl;

    std::shared_ptr<MobilePhone> pHuaWei = std::make_shared<HuaWei>(pGameApp);
    pHuaWei->appRun();

    pHuaWei = std::make_shared<HuaWei>(pTranslateApp);
    pHuaWei->appRun();

    return 0;
    //运行结果:
    //XiaoMi: GameApp Running
    //XiaoMi: TranslateApp Running
    //--------------------------------------------------
    //HuaWei: GameApp Running
    //HuaWei: TranslateApp Running
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值