1. 程式人生 > >c++ 設計模式7 (Bridge 橋模式)

c++ 設計模式7 (Bridge 橋模式)

設計模式 play 復制代碼 復用性 ict 只有一個 mage 單一職責原則 sea

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的擴展模式。

c++ 設計模式7 (Bridge 橋模式)