以下内容均来自GeekBand极客班C++ 设计模式课程(李建忠老师主讲)
完整代码见:https://download.csdn.net/download/qq_41605114/18881737
Bridge
“单一职责”模式:
在软件组件的设计中,如果责任划分不清晰,使用继承得到的结果往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码(典型的Bad smell),这时候的关键是划分责任。
典型模式:
Decorator
Bridge
动机(Motivation)
由于某些类型的固有的实现逻辑,使得它们具有两个变化的维度,乃至多个纬度的变化。
现在有如下示例,一个多平台的消息系统
示例
class Messager
class Messager{
public:
virtual void Login(string username,string password) = 0;
virtual void sendMessage(string message) = 0;
virtual void SendPicture(Image iamge) = 0;
virtual void PlaySound() = 0;
virtual void DrawShape() = 0;
virtual void WriteText() = 0;
virtual void Connect() = 0;
virtual ~Messager(){}
};
提高信息传递的功能
下面有两个平台进行实现,一个PC,一个移动端Mobile
class PC
//平台实现
class PCMessagerBase : public Messager{
public:
virtual void PlaySound(){
//**********
}
virtual void DrawShape(){
//**********
}
virtual void WirteText(){
//**********
}
virtual void Connect(){
//*********
}
};
对于PC平台,还有两个对应的版本
//业务抽象
//经典版本
class PCMessagerLite : public PCMessagerBase{
public:
virtual void Login(string username,string password){
PCMessagerBase::Connect();
//....
}
virtual void sendMessage(string message){
PCMessagerBase::WirteText();
//....
}
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::WirteText();
//....
}
virtual void SendPicture(Image image){
PCMessagerBase::PlaySound();
PCMessagerBase::DrawShape();
//....
}
};
class Mobile
class MobileMessagerBase : public Messager{
public:
virtual void PlaySound(){
//+++++++
}
virtual void DrawShape(){
//+++++++
}
virtual void WriteText(){
//+++++++
}
virtual void Connect(){
//+++++++
}
};
对于Mobile平台,还有两个对应的版本
//经典版本
class MobileMessagerLite : public MobileMessagerBase{
public:
virtual void Login(string username,string password){
MobileMessagerBase::Connect();
//....
}
virtual void sendMessage(string message){
MobileMessagerBase::WirteText();
//....
}
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::WirteText();
//....
}
virtual void SendPicture(Image image){
MobileMessagerBase::PlaySound();
MobileMessagerBase::DrawShape();
//....
}
};
我们观察两个类中的两个函数:
//PC侧的完美版本
class PCMessagerPerfect : public PCMessagerBase{
public:
virtual void Login(string username,string password){
PCMessagerBase::PlaySound();
PCMessagerBase::Connect();
//....
}
};
//Mobile完美版本
class MobileMessagerPerfect : public MobileMessagerBase{
public:
virtual void Login(string username,string password){
MobileMessagerBase::PlaySound();
MobileMessagerBase::Connect();
//....
}
};
高度重复,调用的全是相同的虚函数,完全可以进行重构
我们先将PC端中,继承全部改掉:
//业务抽象
//经典版本
class PCMessagerLite{
PCMessagerBase * messager;
public:
virtual void Login(string username,string password){
messager->Connect();
//....
}
virtual void sendMessage(string message){
messager->WirteText();
//....
}
virtual void SendPicture(Image image){
messager->DrawShape();
//....
}
};
//完美版本
class PCMessagerPerfect{
PCMessagerBase * messager;
public:
virtual void Login(string username,string password){
messager->PlaySound();
messager->Connect();
//....
}
virtual void sendMessage(string message){
messager->PlaySound();
messager->WirteText();
//....
}
virtual void SendPicture(Image image){
messager->PlaySound();
messager->DrawShape();
//....
}
};
Mobile端同理
//经典版本
class MobileMessagerLite{
MobileMessagerBase * messager;
public:
virtual void Login(string username,string password){
messager->Connect();
//....
}
virtual void sendMessage(string message){
messager->WirteText();
//....
}
virtual void SendPicture(Image image){
messager->DrawShape();
//....
}
};
//完美版本
class MobileMessagerPerfect{
MobileMessagerBase * messager;
public:
virtual void Login(string username,string password){
messager->PlaySound();
messager->Connect();
//....
}
virtual void sendMessage(string message){
messager->PlaySound();
messager->WirteText();
//....
}
virtual void SendPicture(Image image){
messager->PlaySound();
messager->DrawShape();
//....
}
};
之后我们就发现,完全可以将这两个字段提取到同一个抽象父类中,恰巧我们现在有MessagerLite
//业务抽象
//经典版本
class MessagerLite{
Messager * messager;
public:
virtual void Login(string username,string password){
messager->Connect();
//....
}
virtual void sendMessage(string message){
messager->WirteText();
//....
}
virtual void SendPicture(Image image){
messager->DrawShape();
//....
}
};
//完美版本
class MessagerPerfect{
Messager * messager;
public:
virtual void Login(string username,string password){
messager->PlaySound();
messager->Connect();
//....
}
virtual void sendMessage(string message){
messager->PlaySound();
messager->WirteText();
//....
}
virtual void SendPicture(Image image){
messager->PlaySound();
messager->DrawShape();
//....
}
};
但是现在有一个问题,Class PCMessagerBase和Class MobileMessagerBase,都还是纯虚函数,因为并没有全部重写Messager类中的全部虚函数
Class MessagerPerfect和MessagerLite类中,又是重写了Messager类中的部分虚函数,显然,Messager的责任冗余且不清晰
所以现在要对Messager进行切割
class Messager{
protected:
MessagerImp * messagerImp;
public:
Messager(MessagerImp * arg):messagerImp(arg){
}
virtual void Login(string username,string password) = 0;
virtual void sendMessage(string message) = 0;
virtual void SendPicture(Image iamge) = 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 PCMessagerBase : public MessagerImp{
public:
virtual void PlaySound(){
//**********
}
virtual void DrawShape(){
//**********
}
virtual void WirteText(){
//**********
}
virtual void Connect(){
//*********
}
};
class MobileMessagerBase : public MessagerImp{
public:
virtual void PlaySound(){
//+++++++
}
virtual void DrawShape(){
//+++++++
}
virtual void WriteText(){
//+++++++
}
virtual void Connect(){
//+++++++
}
};
//业务抽象
//经典版本
class MessagerLite : public Messager{
public:
virtual void Login(string username,string password){
messagerImp->Connect();
//....
}
virtual void sendMessage(string message){
messagerImp->WirteText();
//....
}
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->WirteText();
//....
}
virtual void SendPicture(Image image){
messagerImp->PlaySound();
messagerImp->DrawShape();
//....
}
};
具体调用:
void Process(){
// 运行时装配
MessagerImp * mImp = new PCMessagerBase();
Messager * m = new Messager(mImp);
};
要点总结:
Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自维度的变化,即“子类化”他们。
Bridge模型有时候类似于多继承方案,但是多继承方案往往违背单一职责原则(即一个类只有一个变化的原因),复用性比较差,Bridge模式是比多继承方案更好的解决方法
Bridge模型的应用一般在“两个非常强的变化维度”,有时一个类也有多于两个的变化维度,这时可以使用Bridge的扩展模式。