桥模式(Bridge)
动机
由于某些类型的固有实现逻辑,使得他们具有多个变化的维度。
待解决问题
如何应对多个维度的变化,如何应用面向对象技术使得类型可以轻松的沿着多个方向变化而不引入额外的复杂度。
桥模式定义
将抽象部分(业务功能)与实现部分(平台实现)分离,使得他们都可以独立的变化。
————————GoF
UML
图中imp指针做桥连接两个抽象类
例子:不同平台消息发送软件的不同版本
我们打算设计这样一个发消息的软件,该软件有PC端和移动端两种版本,同时PC和移动端该软件又同时具备精简版和完整版两个版本(多个变化方向)
不使用桥模式,我们很自然的想到:我们手机设计一个发送消息的软件的抽象基类(Messager),然后分别设计基于PC端(PCMessagerBase)和移动端(MobileMessagerBase)的基类继承该抽象基类。最后分别为PC端和移动端在在设计一个Lite版本(PCLite和MobileLite)和一个Perfect版本(PCPerfect和MobilePerfect),分别继承自两个端的类。
代码如下:
class Messager{//消息发送基类
public:
virtual void Login(string userName,string password)=0;
virtual void SendMessage(string messge)=0;
virtual void SendPicture(Image image)=0;
virtual void PalySound()=0;
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;
virtual ~Messager();
};
//平台实现(n)
class PCMessagerBase:public Messager{//PC平台下
public:
virtual void PalySound(){
//PC平台下播放声音功能实现
}
virtual void DrawShape(){
//PC平台下画图功能实现
}
virtual void WriteText(){
//PC平台下写文本功能实现
}
virtual void Connect(){
//PC平台下连接功能实现
}
};
class MobileMessagerBase:public Messager{//移动平台下
public:
virtual void PalySound(){
//移动平台下播放声音功能实现
}
virtual void DrawShape(){
//移动平台下画图功能实现
}
virtual void WriteText(){
//移动平台下写文本功能实现
}
virtual void Connect(){
//移动平台下连接功能实现
}
};
//业务抽象(m)
class PCMessagerLite:public PCMessagerBase{//PC段的精简版软件
public:
virtual void Login(string userName,string password){
PCMessagerBase::Connect();
//PC平台下精简版软件登录的代码设计
}
virtual void SendMessage(string messge){
PCMessagerBase::WriteText();
///PC平台下精简版软件发送消息的代码设计
}
virtual void SendPicture(Image image){
PCMessagerBase::DrawShape();
//PC平台下精简版软件发送图片的代码设计
}
};
class PCMessagerPerfect:public PCMessagerBase{//PC段的完整版软件
public://完备版软件的各个具体功能实现与精简版不同(变化)
virtual void Login(string userName,string password){
PCMessagerBase::PalySound();
/PC平台下完整版软件发送消息的代码设计
PCMessagerBase::Connect();
//...
}
virtual void SendMessage(string messge){
PCMessagerBase::PalySound();
/PC平台下完整版软件发送消息的代码设计.
PCMessagerBase::WriteText();
//...
}
virtual void SendPicture(Image image){
PCMessagerBase::PalySound();
/PC平台下完整版软件发送消息的代码设计
PCMessagerBase::DrawShape();
//....
}
};
//同理移动平台下也有精简版和完整版,两个版本的各个功能实现也不相同
class MobileMessagerLite:public MobileMessagerBase{...};
class MobileMessagerPerfect:public MobileMessagerBase{...};
void Process(){//测试函数
//编译时装配
Messager* m1 = new MobileMessagerLite();
Messager* m2 = new MobileMessagerPerfect();
Messager* m3 = new PCeMessagerLite();
Messager* m4 = new PCMessagerPerfect();
}
分析上述设计,假设我们有n个不同放入平台,m种软件的版本。我们一共需要设计1+n+n*m个类。这种设计造成子类急剧膨胀,且每个类的重复性高。
我们用桥模式设计
/*class Messager{//消息发送基类
public:
virtual void Login(string userName,string password)=0;
virtual void SendMessage(string messge)=0;
virtual void SendPicture(Image image)=0;
virtual void PalySound()=0;
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;
virtual ~Messager();
};*/
//平台实现应该和业务抽象分开
class Messager{//
public:
virtual void Login(string userName,string password)=0;
virtual void SendMessage(string messge)=0;
virtual void SendPicture(Image image)=0;
virtual ~Messager();
};
class MessagerImp{//
public:
virtual void PalySound()=0;
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;
virtual ~MessageImp();
};
//平台实现(n)
class PCMessagerBase:public MessagerImp{//PC平台下
public:
virtual void PalySound(){
//PC平台下播放声音功能实现
}
virtual void DrawShape(){
//PC平台下画图功能实现
}
virtual void WriteText(){
//PC平台下写文本功能实现
}
virtual void Connect(){
//PC平台下连接功能实现
}
};
class MobileMessagerBase:public MessagerImp{//移动平台下
public:
virtual void PalySound(){
//移动平台下播放声音功能实现
}
virtual void DrawShape(){
//移动平台下画图功能实现
}
virtual void WriteText(){
//移动平台下写文本功能实现
}
virtual void Connect(){
//移动平台下连接功能实现
}
};
//业务抽象(m)
class MessagerLite:public Messager{//精简版软件
MessagerImp* messager;//多态指针(桥模式的关键修改位置)
public:
virtual void Login(string userName,string password){
/*PCMessagerBase::Connect();*///桥模式修改
messager->Connect();
//精简版软件登录的代码设计
}
virtual void SendMessage(string messge){
/*PCMessagerBase::WriteText();*///桥模式修改
messager->WriteText();
///精简版软件发送消息的代码设计
}
virtual void SendPicture(Image image){
/*PCMessagerBase::DrawShape();*///桥模式修改
messager->DrawShape();
//精简版软件发送图片的代码设计
}
};
class MessagerPerfect:public MessagerImp{//完整版软件
Messager* messager;//多态指针(桥模式的关键修改位置)
public://完备版软件的各个具体功能实现与精简版不同(变化)
virtual void Login(string userName,string password){
messager->PalySound();
/PC平台下完整版软件发送消息的代码设计
messager->Connect();
//...
}
virtual void SendMessage(string messge){
messager->PalySound();
/PC平台下完整版软件发送消息的代码设计.
messager->WriteText();
//...
}
virtual void SendPicture(Image image){
messager->PalySound();
/PC平台下完整版软件发送消息的代码设计
messager->DrawShape();
//....
}
};
/*~~同理移动平台下也有精简版和完整版,两个版本的各个功能实现也不相同~~
继承转组合之后已经不需要再设计相对应于某个平台的某个本版的类了
class MobileMessagerLite:public MobileMessagerBase{...};
class MobileMessagerPerfect:public MobileMessagerBase{...};*/
void Process(){//测试函数
//运行时装配
MessagerImp* pcImp = new PCMessagerImp();
MessagerImp* mImp = new MobileMessagerImp();
Messager* m1 = new MobileMessagerLite(pcImp );
Messager* m2 = new MobileMessagerPerfect(pcImp );
Messager* m3 = new PCeMessagerLite(mImp);
Messager* m4 = new PCMessagerPerfect(mImp);
}
分析上述设计,假设我们有n个不同放入平台,m种软件的版本。我们一共只需要设计1+n+m个类。桥模式主要设计手段就是用多态指针,设计转组合。将不同的变化方向分离(平台变化和版本变化)使得他们可以独立的变化。