c++ 设计模式7 (Bridge 桥模式)
4.2 Bridge 桥模式
动机:
由于某些类型的固有的实现逻辑,使得它们具有两个变化的维度,乃至多个变化的维度。
代码示例:
实现一个Messager,含有基本功能PlaySound,Connect等,并有PC、Mobile不同的平台实现 和 精简、完美等不同业务功能的版本
实现方法1:
Bridge1.cpp
类的个数:1 + n + m*n,数量巨大且不同类之中有大量重复
重构见方法2
1 class Messager{ 2 public: 3 virtual void Login(string username, string password)=0; 4 virtual void SendMessage(string message)=0; 5 virtual void SendPicture(Image image)=0; 6 7 virtual void PlaySound()=0; 8 virtual void DrawShape()=0; 9 virtual void WriteText()=0; 10 virtual void Connect()=0; 11 12 virtual ~Messager(){} 13 }; 14 15 16 //平台实现 17 18 class PCMessagerBase : public Messager{ 19 public: 20 21 virtual void PlaySound(){ 22 //********** 23 } 24 virtual void DrawShape(){ 25 //********** 26 } 27 virtual void WriteText(){ 28 //********** 29 } 30 virtual void Connect(){ 31 //********** 32 } 33 }; 34 35 class MobileMessagerBase : public Messager{ 36 public: 37 38 virtual void PlaySound(){ 39 //========== 40 } 41 virtual void DrawShape(){ 42 //========== 43 } 44 virtual void WriteText(){ 45 //========== 46 } 47 virtual void Connect(){ 48 //========== 49 } 50 }; 51 52 53 54 //业务抽象 55 56 class PCMessagerLite : public PCMessagerBase { 57 public: 58 59 virtual void Login(string username, string password){ 60 61 PCMessagerBase::Connect(); 62 //........ 63 } 64 virtual void SendMessage(string message){ 65 66 PCMessagerBase::WriteText(); 67 //........ 68 } 69 virtual void SendPicture(Image image){ 70 71 PCMessagerBase::DrawShape(); 72 //........ 73 } 74 }; 75 76 77 78 class PCMessagerPerfect : public PCMessagerBase { 79 public: 80 81 virtual void Login(string username, string password){ 82 83 PCMessagerBase::PlaySound(); 84 //******** 85 PCMessagerBase::Connect(); 86 //........ 87 } 88 virtual void SendMessage(string message){ 89 90 PCMessagerBase::PlaySound(); 91 //******** 92 PCMessagerBase::WriteText(); 93 //........ 94 } 95 virtual void SendPicture(Image image){ 96 97 PCMessagerBase::PlaySound(); 98 //******** 99 PCMessagerBase::DrawShape(); 100 //........ 101 } 102 }; 103 104 105 class MobileMessagerLite : public MobileMessagerBase { 106 public: 107 108 virtual void Login(string username, string password){ 109 110 MobileMessagerBase::Connect(); 111 //........ 112 } 113 virtual void SendMessage(string message){ 114 115 MobileMessagerBase::WriteText(); 116 //........ 117 } 118 virtual void SendPicture(Image image){ 119 120 MobileMessagerBase::DrawShape(); 121 //........ 122 } 123 }; 124 125 126 class MobileMessagerPerfect : public MobileMessagerBase { 127 public: 128 129 virtual void Login(string username, string password){ 130 131 MobileMessagerBase::PlaySound(); 132 //******** 133 MobileMessagerBase::Connect(); 134 //........ 135 } 136 virtual void SendMessage(string message){ 137 138 MobileMessagerBase::PlaySound(); 139 //******** 140 MobileMessagerBase::WriteText(); 141 //........ 142 } 143 virtual void SendPicture(Image image){ 144 145 MobileMessagerBase::PlaySound(); 146 //******** 147 MobileMessagerBase::DrawShape(); 148 //........ 149 } 150 }; 151 152 153 void Process(){ 154 //编译时装配 155 Messager *m = 156 new MobileMessagerPerfect(); 157 }
重构步骤:
1.继承转组合,将PCMessagerBase,Mobilemessager声明为字段;
1 class PCMessagerLite { 2 PCMessagerBase *messager; 3 public: 4 5 virtual void Login(string username, string password){ 6 7 messager -> Connect(); 8 //........ 9 } 10 virtual void SendMessage(string message){ 11 12 messager -> WriteText(); 13 //........ 14 } 15 virtual void SendPicture(Image image){ 16 17 messager -> DrawShape(); 18 //........ 19 } 20 }; 21 22 class PCMessagerLite { 23 MobileMessagerBase *messager; 24 public: 25 26 virtual void Login(string username, string password){ 27 28 messager -> Connect(); 29 //........ 30 } 31 virtual void SendMessage(string message){ 32 33 messager -> WriteText(); 34 //........ 35 } 36 virtual void SendPicture(Image image){ 37 38 messager -> DrawShape(); 39 //........ 40 } 41 };
2.观察上述两个类,发现只有 *messager 声明不同,故采用基类声明,运行时多态调用方式,创建不同的 PCMessagerBase,Mobilemessager;
1 class PCMessagerLite { 2 Messager *messager; // = new PCMessagerBase()或 MobileMessagerBase() 3 public: 4 5 virtual void Login(string username, string password){ 6 7 messager -> Connect(); 8 //........ 9 } 10 virtual void SendMessage(string message){ 11 12 messager -> WriteText(); 13 //........ 14 } 15 virtual void SendPicture(Image image){ 16 17 messager -> DrawShape(); 18 //........ 19 } 20 };
3.考虑步骤2的代码,Messager类是纯虚基类(抽象类),不能实例化,故= new ...不成立。
分析产生这种状况的原因,是Login,SendPicture等与平台实现相关的方法,和PlaySound,DrawShape等与业务功能相关的方法不应该在一个类里。
将其拆分,得到MessagerImp类。
同时将MessagerLite,MessagerPerfect类中相同的MesseagerImp字段提到父类Messager,得到重构后的代码
注意运行时装配
1 class Messager{ 2 protected: 3 MessagerImp* messagerImp;//... 4 public: 5 virtual void Login(string username, string password)=0; 6 virtual void SendMessage(string message)=0; 7 virtual void SendPicture(Image image)=0; 8 9 virtual ~Messager(){} 10 }; 11 12 class MessagerImp{ 13 public: 14 virtual void PlaySound()=0; 15 virtual void DrawShape()=0; 16 virtual void WriteText()=0; 17 virtual void Connect()=0; 18 19 virtual MessagerImp(){} 20 }; 21 22 23 //平台实现 n 24 class PCMessagerImp : public MessagerImp{ 25 public: 26 27 virtual void PlaySound(){ 28 //********** 29 } 30 virtual void DrawShape(){ 31 //********** 32 } 33 virtual void WriteText(){ 34 //********** 35 } 36 virtual void Connect(){ 37 //********** 38 } 39 }; 40 41 class MobileMessagerImp : public MessagerImp{ 42 public: 43 44 virtual void PlaySound(){ 45 //========== 46 } 47 virtual void DrawShape(){ 48 //========== 49 } 50 virtual void WriteText(){ 51 //========== 52 } 53 virtual void Connect(){ 54 //========== 55 } 56 }; 57 58 59 60 //业务抽象 m 61 62 //类的数目:1+n+m 63 64 class MessagerLite :public Messager { 65 66 67 public: 68 69 virtual void Login(string username, string password){ 70 71 messagerImp->Connect(); 72 //........ 73 } 74 virtual void SendMessage(string message){ 75 76 messagerImp->WriteText(); 77 //........ 78 } 79 virtual void SendPicture(Image image){ 80 81 messagerImp->DrawShape(); 82 //........ 83 } 84 }; 85 86 87 88 class MessagerPerfect :public Messager { 89 90 91 public: 92 93 virtual void Login(string username, string password){ 94 95 messagerImp->PlaySound(); 96 //******** 97 messagerImp->Connect(); 98 //........ 99 } 100 virtual void SendMessage(string message){ 101 102 messagerImp->PlaySound(); 103 //******** 104 messagerImp->WriteText(); 105 //........ 106 } 107 virtual void SendPicture(Image image){ 108 109 messagerImp->PlaySound(); 110 //******** 111 messagerImp->DrawShape(); 112 //........ 113 } 114 }; 115 116 117 118 119 void Process(){ 120 //运行时装配 121 MessagerImp* mImp=new PCMessagerImp(); 122 Messager *m =new Messager(mImp); 123 }
模式定义:
将抽象部分(业务功能)与实现部分(平台实现)分离,使他们都可以独立地变化。
类图:
要点总结:
Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固有的绑定关系,使得抽象的实现可以沿着各自的维度来变化。所谓抽象和实现研制各自维度的变化,即“子类化”他们。
Bridge模式有时候类似于多继承方案,但是多继承方案往往违背单一职责原则(即一个雷只有一个变化的原因),复用性较差。Bridge模式是比多继承更好的解决方案。
Bridge模式的应用一般在“两个非常强的变化维度”有时一个类也有多余两个的变化维度,这是可以使用Bridge的扩展模式。