设计模式C++005__桥模式
设计模式C++005__桥模式
也是组合模式 的具体体现。
1、动机:
由于某些类型的古有的实现逻辑,使得他们具有两个变化的维度,乃至多个维度的变化。
?如何应对这种“多维度的变化”,如何利用面向对象技术来使得类型可以轻松地沿着两个乃至多个方向变化,而不引入额外的复杂度。
2、桥模式:
将抽象部分(业务功能)与实现部分(平台实现)分离,使他们都可以独立的变化。--GoF
3、示例:
假如有一个通信模块类Message,有一些方法:Login, SendMessage(), SendPicture(), 还有一些方法:PlaySound(),DrawShape(),WriteText(),Connect()
假设我们需要同时支持PC和Mobile平台.就可以新增两个类,分别继承Message,实现具体方法。
然后又有需求,需要每个平台要有精简版和完美版。
以PC端精简版,为例:需要登录{联网},发送消息{输入文字},发送图片{选图}的基本功能。
以PC端完美版为例:需要登录{联网,同时播放声音};发送消息时{输入文字,同时播放声音},发送图片{选图,播放声音}
Mobile,也和PC端业务功能基本一致。
如果采用继承实现如下:
class Messager{
public:
virtual void Login(string username, string password)=0;
virtual void SendMessage(string message)=0;
virtual void SendPicture(Image image)=0;
virtual void PlaySound()=0;
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;
virtual ~Messager(){}
};
//平台实现
class PCMessagerBase : public Messager{
public:
virtual void PlaySound(){
//**********
}
virtual void DrawShape(){
//**********
}
virtual void WriteText(){
//**********
}
virtual void Connect(){
//**********
}
};
class MobileMessagerBase : public Messager{
public:
virtual void PlaySound(){
//==========
}
virtual void DrawShape(){
//==========
}
virtual void WriteText(){
//==========
}
virtual void Connect(){
//==========
}
};
//业务抽象
class PCMessagerLite : public PCMessagerBase {
public:
virtual void Login(string username, string password){
PCMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
PCMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
PCMessagerBase::DrawShape();
//........
}
};
class PCMessagerPerfect : public PCMessagerBase {
public:
virtual void Login(string username, string password){
PCMessagerBase::PlaySound();
//********
PCMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
PCMessagerBase::PlaySound();
//********
PCMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
PCMessagerBase::PlaySound();
//********
PCMessagerBase::DrawShape();
//........
}
};
class MobileMessagerLite : public MobileMessagerBase {
public:
virtual void Login(string username, string password){
MobileMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
MobileMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
MobileMessagerBase::DrawShape();
//........
}
};
class MobileMessagerPerfect : public MobileMessagerBase {
public:
virtual void Login(string username, string password){
MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::DrawShape();
//........
}
};
void Process(){
//编译时装配
Messager *m =
new MobileMessagerPerfect();
}
针对Lite版本,PC和Mobile大部分是一样函数调用。我们发现继承导致子类膨胀了。可以使用组合的方式替代继承,将功能的编译时装配推迟到运行时。
class PCMessagerLite {
PCMessagerBase *message;
public:
virtual void Login(string username, string password){
message->Connect();//指针调用
//........
}
virtual void SendMessage(string message){
message->WriteText();//指针调用
//........
}
virtual void SendPicture(Image image){
message->DrawShape();//指针调用
//........
}
};
class MobileMessagerLite {
MobileMessagerBase *message;
public:
virtual void Login(string username, string password){
message->Connect();//指针调用
//........
}
virtual void SendMessage(string message){
message->WriteText();//指针调用
//........
}
virtual void SendPicture(Image image){
message->DrawShape();//指针调用
//........
}
};
又发现可以重构的点,PCMessagerBase *message; MobileMessagerBase *message; 这两个变量有相同的基类。
进而,把他们合并为一个基类Messager :
class PCMessagerLite {
Messager *message; //利用组合替代继承之后,未来,运行时就是PCMessagerBase 类了
public:
virtual void Login(string username, string password){
message->Connect();//指针调用
//........
}
virtual void SendMessage(string message){
message->WriteText();//指针调用
//........
}
virtual void SendPicture(Image image){
message->DrawShape();//指针调用
//........
}
};
class MobileMessagerLite {
Messager *message; //未来,运行时就是MobileMessagerBase 类了。
public:
virtual void Login(string username, string password){
message->Connect();//指针调用
//........
}
virtual void SendMessage(string message){
message->WriteText();//指针调用
//........
}
virtual void SendPicture(Image image){
message->DrawShape();//指针调用
//........
}
};
进而,两个类class PCMessagerLite,class MobileMessagerLite可以合二为一了,合并为MessagerLite类。
class MessagerLite {
Messager *message; //利用组合替代继承之后,未来,运行时就是PCMessagerBase 类(或者MobileMessageBase)了 。但是有一个问题,这里的PCMessagerBase /MobileMessagerBase 是一个抽象类,运行时new出来的是一个纯虚类。运行时创建的 new PCMessagerBase(); 对象,里面的函数都是虚函数。不可以调用。 我把该类再继承自Message呢?也不太行,MessagerLite 只实现了Message的部分虚成员函数。C++中父类声明的所有虚函数,子类是必须要实现的。
public:C++中父类声明的所有虚函数,子类是必须要实现的。
virtual void Login(string username, string password){
message->Connect();//指针调用
//........
}
virtual void SendMessage(string message){
message->WriteText();//指针调用
//........
}
virtual void SendPicture(Image image){
message->DrawShape();//指针调用
//........
}
};
class PCMessagerPerfect和class MobileMessagerPerfect;同样可以合并,为:MessagerPerfect
class MessagerPerfect {
Messager *message; //利用组合替代继承之后,未来,运行时就是PCMessagerBase 类(或者MobileMessageBase)了 。但是有一个问题,这里的PCMessagerBase /MobileMessagerBase 是一个抽象类,运行时new出来的是一个纯虚类。运行时创建的 new PCMessagerBase(); 对象,里面的函数都是虚函数。不可以调用。 我把该类再继承自Message呢?也不太行,MessagerPerfact 只实现了Message的部分虚成员函数。C++中父类声明的所有虚函数,子类是必须要实现的。
public:
virtual void Login(string username, string password){
message->PlaySound();
//********
message->Connect();
//........
}
virtual void SendMessage(string message){
message->PlaySound();
//********
message->WriteText();
//........
}
virtual void SendPicture(Image image){
message->PlaySound();
//********
message->DrawShape();
//........
}
};
上述代码的问题:
利用组合替代继承之后,未来,运行时就是PCMessagerBase 类(或者MobileMessageBase)了 。但是有一个问题,这里的PCMessagerBase /MobileMessagerBase 是一个抽象类,运行时new出来的是一个纯虚类。运行时创建的 new PCMessagerBase(); 对象,里面的函数都是虚函数。不可以调用。 我把该类再继承自Message呢?也不太行,MessagerPerfact 只实现了Message的部分虚成员函数。C++中父类声明的所有虚函数,子类是必须要实现的。
这里如何解决呢??
必须拆分父类中的虚函数。拆分到两个类中。
Messager{Login(),SendMessage(),SendPicture}
class MessagerImp{PlaySound(),DrawShape,WriteText,Connect}
class Messager{
public:
virtual void Login(string username, string password)=0;
virtual void SendMessage(string message)=0;
virtual void SendPicture(Image image)=0;
virtual ~Messager(){}
};
class MessagerImp{
public:
virtual void PlaySound()=0;
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;
virtual MessagerImp(){}
};
//然后
//class MessagerLite, class MessagerPerfect; 拆分后,这两个类的结构是这样的。
class MessagerLite : public Message {
MessagerImpl *messageImpl; //...
virtual void Login(string username, string password){
messageImpl->Connect();//指针调用
//........
}
virtual void SendMessage(string message){
messageImpl->WriteText();//指针调用
//........
}
virtual void SendPicture(Image image){
messageImpl->DrawShape();//指针调用
//........
}
};
class MessagerPerfect: public Message {
MessagerImpl *messageImpl; //...
public:
virtual void Login(string username, string password){
messageImpl->PlaySound();
//********
messageImpl->Connect();
//........
}
virtual void SendMessage(string message){
messageImpl->PlaySound();
//********
messageImpl->WriteText();
//........
}
virtual void SendPicture(Image image){
messageImpl->PlaySound();
//********
messageImpl->DrawShape();
//........
}
};
同样的画面又出现了。
马丁·秃了告诉我们,如果不同类当中,如果多次声明了继承自同一个父类的子类指针时,可以抽取一层抽象层。把这个子类对象放到一个抽象类里面。这里我们刚好有一个Message抽象类,把它作为Message的一个成员变量即可。
class Messager{
protected:
MessagerImp* messagerImp;//...
public:
Message(MessagerImp* msgImp):messagerImp(msgImp){}//父类的构造函数中要给这个成员赋值。
virtual void Login(string username, string password)=0;
virtual void SendMessage(string message)=0;
virtual void SendPicture(Image image)=0;
virtual ~Messager(){}
};
class MessagerImp{
public:
virtual void PlaySound()=0;
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;
virtual MessagerImp(){}
};
最终版本:
class Messager{
protected:
MessagerImp* messagerImp;//...
public:
virtual void Login(string username, string password)=0;
virtual void SendMessage(string message)=0;
virtual void SendPicture(Image image)=0;
virtual ~Messager(){}
};
class MessagerImp{
public:
virtual void PlaySound()=0;
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;
virtual MessagerImp(){}
};
//平台实现 n
class PCMessagerImp : public MessagerImp{
public:
virtual void PlaySound(){
//**********
}
virtual void DrawShape(){
//**********
}
virtual void WriteText(){
//**********
}
virtual void Connect(){
//**********
}
};
class MobileMessagerImp : public MessagerImp{
public:
virtual void PlaySound(){
//==========
}
virtual void DrawShape(){
//==========
}
virtual void WriteText(){
//==========
}
virtual void Connect(){
//==========
}
};
//业务抽象 m
//类的数目:1+n+m
class MessagerLite :public Messager {
public:
//这里要有子类构造函数中要有,调用父类有参构造函数的步骤,这里是初始化列表的方式。这样才能符合构造,析构的顺序。:Messager(*msg){} -->MessagerLite(Messager *msg){} -->~MessagerLite(){} --> ~Messager(){}。
MessagerLite(Messager *msg):Messager(*msg){}
virtual void Login(string username, string password){
messagerImp->Connect();
//........
}
virtual void SendMessage(string message){
messagerImp->WriteText();
//........
}
virtual void SendPicture(Image image){
messagerImp->DrawShape();
//........
}
};
class MessagerPerfect :public Messager {
public:
virtual void Login(string username, string password){
messagerImp->PlaySound();
//********
messagerImp->Connect();
//........
}
virtual void SendMessage(string message){
messagerImp->PlaySound();
//********
messagerImp->WriteText();
//........
}
virtual void SendPicture(Image image){
messagerImp->PlaySound();
//********
messagerImp->DrawShape();
//........
}
};
void Process(){
//运行时装配
MessagerImp* mImp=new PCMessagerImp();
Messager *m =new Messager(mImp);
}
3、结构:
4、要点总结:
- Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自维度变化,即子类化他们。
- Bridge模式有时候类似于多继承方案,但是多继承方案往往违背单一职责原则(即一个类只有一个变化的原因),复用性比较差,Bridge 模式是比多继承方案更好的解决方法。
- Bridge模式的应用一般在“两个非常强的变化维度”,有时一个类也有多于两个的变化维度,这时可以使用Bridge的扩展模式。