桥接
定义:
桥接模式(Bridge)是一种结构型设计模式。Bridge模式基于类的最小设计原则,通过使用封装、聚合及继承等行为让不同的类承担不同的职责。它的主要特点是把抽象(Abstraction)与行为实现(Implementation)分离开来,从而可以保持各部分的独立性以及应对他们的功能扩展。
实现指的是抽象类和它的派生类用来实现自己的对象。
桥接模式核心意图就是把实现独立出来,让它们各自变化,使得每种实现的变化不会影响其他实现,从而达到应对变化的目的。
为什么要优先使用合成/聚合原则?
(1)对象的继承关系是在编译时就定义好了的。所以无法在执行时改变从父类继承的实现。子类的实现与它的父类有很紧密的依赖关系。以至于父类实现的不论什么变化必定会导致子类发生变化。当你须要复用子类时。假设继承下来的实现不适合解决新的问题。则父类必须重写或被其它更适合的类替换。
这样的依赖关系限制了灵活性并终于限制了复用性。
(2)优先使用合成/聚合原则有助于你保持每一个类被封装,并被集中在单个任务上。这样类和类继承层次会保持较小规模,而且不太可能增长为不可控制的庞然大物。
盲目使用继承会造成麻烦,本质原因是什么?
继承是一种强耦合的结构。父类变,子类就必需要变。所以,我们在用继承时,一定要在是“is-a”的关系时再考虑使用,而不是不论什么时候都去使用。
优点:
(1)实现了抽象和实现部分的分离
桥接模式分离了抽象部分和实现部分,从而极大的提供了系统的灵活性,让抽象部分和实现部分独立开来,分别定义接口,这有助于系统进行分层设计,从而产生更好的结构化系统。对于系统的高层部分,只需要知道抽象部分和实现部分的接口就可以了。
(2)更好的可扩展性
由于桥接模式把抽象部分和实现部分分离了,从而分别定义接口,这就使得抽象部分和实现部分可以分别独立扩展,而不会相互影响,大大的提供了系统的可扩展性。
(3)可动态的切换实现
由于桥接模式实现了抽象和实现的分离,所以在实现桥接模式时,就可以实现动态的选择和使用具体的实现。
(4)实现细节对客户端透明,可以对用户隐藏实现细节。
缺点:
(1)桥接模式的引入增加了系统的理解和设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计和编程。
(2)桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围有一定的局限性。
使用场景:
(1)如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
(2)抽象化角色和实现化角色可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。
(3)一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
(4)虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理这两者。
(5)对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用
实现系统可能由多角度分类,每一种分类都有可能变化,那么就把这种多角度分离出来让它们独立变化,减少它们之间的耦合。
在发现需要多角度去分类实现对象,而只用继承会造成大量类的增加,不能满足开放-封闭原则时,就应该要考虑适用桥接模式了。
UML图:
1.Client 调用端
这是Bridge模式的调用者。
2.抽象类(Abstraction)
抽象类接口维护对行为实现(implementation)的引用。它的角色就是桥接类。
3.RefinedAbstraction
这是Abstraction的子类。
4.Implementor
行为实现类接口(Abstraction接口定义了基于Implementor接口的更高层次的操作)
5.ConcreteImplementor
Implementor的子类
#include <iOStream>
#include <string>
using namespace std;
//
class Implementor
{
public:
Implementor(){}
virtual ~Implementor(){}
virtual void operation() = 0;
};
//
class ConcreteImplementorA:public Implementor
{
public:
ConcreteImplementorA(){}
~ConcreteImplementorA(){}
void operation()
{
cout<<"ConcreteImplementorA"<<endl;
}
};
class ConcreteImplementorB:public Implementor
{
public:
ConcreteImplementorB(){}
~ConcreteImplementorB(){}
void operation()
{
cout<<"ConcreteImplementorB"<<endl;
}
};
class Abstraction
{
public:
Abstraction(){}
virtual ~Abstraction(){}
virtual void operation() = 0;
};
class definedAbstraction: public Abstraction
{
public:
DefinedAbstraction(Implementor* absImp_):absImp(absImp_){}
~DefinedAbstraction(){}
void operation()
{
absImp->operation();
}
private:
Implementor* absImp;
};
int main()
{
Implementor* absImp1 = new ConcreteImplementorA();
Abstraction* abs1 = new DefinedAbstraction(absImp1);
abs1->operation();
Implementor* absImp2 = new ConcreteImplementorB();
Abstraction* abs2 = new DefinedAbstraction(absImp2);
abs2->operation();
return 0;
}
例:
#include <iostream>
#include <string>
using namespace std;
//手机软件抽象类
class HandsetSoft
{
public:
virtual void Run()=0;
};
//游戏具体类
class HandsetGame:public HandsetSoft
{
public:
void Run()
{
cout<<"运行手机游戏"<<endl;
}
};
//手机通讯录具体类
class HandsetAddressList:public HandsetSoft
{
public:
void Run()
{
cout<<"运行手机通讯录"<<endl;
}
};
//手机品牌类
class HandsetBrand
{
protected:
HandsetSoft *soft;
public:
void setHandsetSoft(HandsetSoft *soft_)
{
soft=soft_;
}
virtual void Run()=0;
};
//手机品牌N
class HandsetBrandN:public HandsetBrand
{
public:
void Run()
{
soft->Run();
}
};
//手机品牌M
class HandsetBrandM:public HandsetBrand
{
public:
void Run()
{
soft->Run();
}
};
int main()
{
HandsetBrand *ab;
ab=new HandsetBrandN();//N品牌手机
ab->setHandsetSoft(new HandsetGame());
ab->Run();
ab->setHandsetSoft(new HandsetAddressList());
ab->Run();
ab=new HandsetBrandM();//M品牌手机
ab->setHandsetSoft(new HandsetGame());
ab->Run();
ab->setHandsetSoft(new HandsetAddressList());
ab->Run();
return 0;
}