1. 作业
桥梁模式完全是为了解决继承的缺点而设计的模式。继承的缺点是什么?即强侵入性,父类拥有的方法,子类必须照盘接收,如果只有这两层结构到没什么,假设是三层结构,子类下面还有子子类。突然有一天子类想重写父类的某个方法,但是子子类又想保持父类的方法实现,咋办?
意图:将抽象部分和实现部分分离,使他们都可以独立的变化。
继承恰恰就死抽象和实现耦合在一起的。关系够清楚了的吧。
2. UML类图
参与者:
Abstraction:定义抽象类接口,同时维护一个指向Impementor类型的指针。
RefinedAbstraction:实现扩充Abstraction定义的接口。
Impementor:定义实现类的接口,它的接口不必和Abstraction相同。一般来讲Impementor接口仅仅定义了基本操作,而Abstraction则定义了基于这些基本操作的较高层次操作。
Concrete Impementor:Impementor接口的具体实现。
3. 实现
举例:相信80,90后都经历过这样一个变迁,小时候家里用的是白炽灯,开关是拉线开关,随着发展,节能灯取代白炽灯,按钮开关取代了拉线开关。开关和灯泡的关系可以看成是继承关系,因为开关可以看作是灯泡的一部分,灯泡完全拥有开关,如果真是使用继承设计,那么将无法应对开关和灯泡的变迁了。看看桥梁是怎么做的。
代码:
#include <iostream>
using namespace std;
//实现化角色
//电灯
class Light
{
public:
virtual void poweroOn() = 0;
virtual void powerOff() = 0;
};
//具体实现化角色
//白炽灯
class FilamentLight :public Light
{
public:
virtual void poweroOn()
{
cout << "白炽灯打开!" << endl;
}
virtual void powerOff()
{
cout << "白炽灯关闭!" << endl;
}
};
//节能灯
class EfficientLight :public Light
{
public:
virtual void poweroOn()
{
cout << "节能灯打开!" << endl;
}
virtual void powerOff()
{
cout << "节能灯关闭!" << endl;
}
};
//抽象角色定义
//开关
class Switch
{
public:
Switch(Light *light) :m_pLight(light){}
virtual void on() = 0;
virtual void off() = 0;
void setLight(Light *light){ m_pLight = light; }
protected:
Light *m_pLight;
};
//修正抽象化角色
//拉线开关
class PullChainSwitch :public Switch
{
public:
PullChainSwitch(Light *light) :Switch(light){}
virtual void on()
{
cout << "拉线开关打开:";
m_pLight->poweroOn();
}
virtual void off()
{
cout << "拉线开关关闭:";
m_pLight->powerOff();
}
};
//按钮开关
class ButtonSwitch :public Switch
{
public:
ButtonSwitch(Light *light) :Switch(light){}
virtual void on()
{
cout << "按钮开关打开:";
m_pLight->poweroOn();
}
virtual void off()
{
cout << "按钮开关关闭:";
m_pLight->powerOff();
}
};
//场景
int main()
{
//创建具体实现化角色
Light *filamentLight = new FilamentLight;//白炽灯
Light *efficientLight = new EfficientLight;//节能灯
//创建具体抽象化角色
Switch * pullChainSwitch = new PullChainSwitch(filamentLight);//白炽灯一般配拉线开关
pullChainSwitch->on();
//生活好了换了节能灯
pullChainSwitch->setLight(efficientLight);
pullChainSwitch->on();
//生活好了又换了按钮开关了
Switch * buttonSwitch = new ButtonSwitch(efficientLight);
buttonSwitch->on();
return 0;
}
结果:
拉线开关打开:白炽灯打开!
拉线开关打开:节能灯打开!
按钮开关打开:节能灯打开!
请按任意键继续. . .
4. 优缺点
优点:
1.抽象与实现分离,抽象部分。实现不受抽象的约束了。
2.抽象和实现都非常好扩充。
3.客户不用关心细节的实现,抽象层通过聚合关系进行了封装。
缺点:
1.桥接模式的使用会增加系统的理解与设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程。
2.桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性,如何正确识别两个独立维度也需要一定的经验积累。
5. 使用场景
1.不希望使用继承的场景,不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统
2.抽象接口不稳定的场景,接口有可能会改变。
6. 总结
桥梁模式是针对继承的不足提出了,一般当继承大于等于二层时,才考虑使用桥梁模式。此时才能显示出抽象变化的方便。