引言
假如有三个品牌的手机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
}