4.2 Bridge 桥模式
动机:
由于某些类型的固有的实现逻辑,使得它们具有两个变化的维度,乃至多个变化的维度。
代码示例:
实现一个Messager,含有基本功能PlaySound,Connect等,并有PC、Mobile不同的平台实现 和 精简、完美等不同业务功能的版本
实现方法1:
Bridge1.cpp
类的个数:1 + n + m*n,数量巨大且不同类之中有大量重复
重构见方法2
class Messager{
public:
virtual void Login(string username, string password)=;
virtual void SendMessage(string message)=;
virtual void SendPicture(Image image)=; virtual void PlaySound()=;
virtual void DrawShape()=;
virtual void WriteText()=;
virtual void Connect()=; 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();
}
重构步骤:
1.继承转组合,将PCMessagerBase,Mobilemessager声明为字段;
class PCMessagerLite {
PCMessagerBase *messager;
public: virtual void Login(string username, string password){ messager -> Connect();
//........
}
virtual void SendMessage(string message){ messager -> WriteText();
//........
}
virtual void SendPicture(Image image){ messager -> DrawShape();
//........
}
}; class PCMessagerLite {
MobileMessagerBase *messager;
public: virtual void Login(string username, string password){ messager -> Connect();
//........
}
virtual void SendMessage(string message){ messager -> WriteText();
//........
}
virtual void SendPicture(Image image){ messager -> DrawShape();
//........
}
};
2.观察上述两个类,发现只有 *messager 声明不同,故采用基类声明,运行时多态调用方式,创建不同的 PCMessagerBase,Mobilemessager;
class PCMessagerLite {
Messager *messager; // = new PCMessagerBase()或 MobileMessagerBase()
public: virtual void Login(string username, string password){ messager -> Connect();
//........
}
virtual void SendMessage(string message){ messager -> WriteText();
//........
}
virtual void SendPicture(Image image){ messager -> DrawShape();
//........
}
};
3.考虑步骤2的代码,Messager类是纯虚基类(抽象类),不能实例化,故= new ...不成立。
分析产生这种状况的原因,是Login,SendPicture等与平台实现相关的方法,和PlaySound,DrawShape等与业务功能相关的方法不应该在一个类里。
将其拆分,得到MessagerImp类。
同时将MessagerLite,MessagerPerfect类中相同的MesseagerImp字段提到父类Messager,得到重构后的代码
注意运行时装配
class Messager{
protected:
MessagerImp* messagerImp;//...
public:
virtual void Login(string username, string password)=;
virtual void SendMessage(string message)=;
virtual void SendPicture(Image image)=; virtual ~Messager(){}
}; class MessagerImp{
public:
virtual void PlaySound()=;
virtual void DrawShape()=;
virtual void WriteText()=;
virtual void Connect()=; 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: 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);
}
模式定义:
将抽象部分(业务功能)与实现部分(平台实现)分离,使他们都可以独立地变化。
类图:
要点总结:
Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固有的绑定关系,使得抽象的实现可以沿着各自的维度来变化。所谓抽象和实现研制各自维度的变化,即“子类化”他们。
Bridge模式有时候类似于多继承方案,但是多继承方案往往违背单一职责原则(即一个雷只有一个变化的原因),复用性较差。Bridge模式是比多继承更好的解决方案。
Bridge模式的应用一般在“两个非常强的变化维度”有时一个类也有多余两个的变化维度,这是可以使用Bridge的扩展模式。