目錄
- 前言
- Bridge設計模式
-
- 1.模式動機
- 2.示例1
- 3.示例2:圖形和顔色
- 4.模式定義
- 5.模式結構
- 6.要點總結
前言
在學習侯捷老師的有關設計模式的課程(李建忠老師主講)中,老師對23種設計模式的有自己的劃分,如下。是以老師講解是按照這種順序講解。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLzMWO2MWY4EmM2UTOhRTOidTM5QDZ0IWO3ADN1EGZxkzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
單一職責:
Bridge設計模式
1.模式動機
由于某些類型的固有的實作邏輯,使得它們具有兩個變化的次元,乃至多個緯度的變化。
是以Bridge模式的動機就是應對“
多元度的變化
”。
看文字描述表枯燥,下面舉幾個例子:
- 商城系統中的電腦分類:如
,這是兩個次元的變化。電腦類型+電腦品牌
設計模式之橋模式(Bridge)前言Bridge設計模式 -
兩種變化的次元圖形形狀+顔色填充
設計模式之橋模式(Bridge)前言Bridge設計模式
下面是橋模式的實際看法場景:
參考至:參考
下面給一個具體的案例:
2.示例1
先看代碼,後面解釋會清楚點。
#include <iostream>
using namespace std;
//實作抽象
class MessagerImp{
public:
virtual void PlaySound() = 0;
virtual void DrawShape() = 0;
virtual void WriteText() = 0;
virtual void Connect() = 0;
virtual ~MessagerImp(){}
};
//平台實作
class PCMessagerImp : public MessagerImp{//PC平台
public:
virtual void PlaySound(){
//**********
cout << "PC::PlaySound ,播放聲音." << endl;
}
virtual void DrawShape(){
//**********
cout << "PC::DrawShape ,畫圖形." << endl;
}
virtual void WriteText(){
//**********
cout << "PC::WriteText ,寫文本." << endl;
}
virtual void Connect(){
//**********
cout << "PC::Connect ,登入連接配接." << endl;
}
};
class MobileMessagerImp : public MessagerImp{//PC平台
public:
virtual void PlaySound(){
//**********
cout << "Mobile::PlaySound ,播放聲音." << endl;
}
virtual void DrawShape(){
//**********
cout << "Mobile::DrawShape ,畫圖形." << endl;
}
virtual void WriteText(){
//**********
cout << "Mobile::WriteText ,寫文本." << endl;
}
virtual void Connect(){
//**********
cout << "Mobile::Connect ,登入連接配接." << endl;
}
};
//業務功能抽象
class Messager{
protected:
MessagerImp* messagerImp;//拿着實作(MessagerImp)的基類指針
Messager(MessagerImp* _messagerImp) : messagerImp(_messagerImp){}
public:
virtual void Login(string username, string password) = 0;
virtual void SendMessage(string message) = 0;
virtual void SendPicture() = 0;
virtual ~Messager(){}
};
//業務實作
class MessagerLite :public Messager {//Lite
public:
MessagerLite(MessagerImp* _messagerImp) : Messager(_messagerImp){}
virtual void Login(string username, string password){
cout << "Lite::Login , 登入..." << endl;
messagerImp->Connect();
//........
}
virtual void SendMessage(string message){
cout << "Lite::SendMessage , 發送登入消息..." << endl;
messagerImp->WriteText();
//........
}
virtual void SendPicture(){
cout << "Lite::SendMessage , 發送圖檔..." << endl;
messagerImp->DrawShape();
//........
}
};
class MessagerPerfect :public Messager {
public:
MessagerPerfect(MessagerImp* _messagerImp) : Messager(_messagerImp){}
virtual void Login(string username, string password){
cout << "Perfect::Login , 登入..." << endl;
messagerImp->PlaySound();
//********
messagerImp->Connect();
//........
}
virtual void SendMessage(string message){
cout << "Perfect::SendMessage , 發送登入消息..." << endl;
messagerImp->PlaySound();
//********
messagerImp->WriteText();
//........
}
virtual void SendPicture(){
cout << "Perfect::SendMessage , 發送圖檔..." << endl;
messagerImp->PlaySound();
//********
messagerImp->DrawShape();
//........
}
};
int main()
{
Messager* mes = new MessagerLite(new PCMessagerImp);//生成精簡版(Lite)Message,在PC平台下
mes->Login("xxx","123");
mes->SendMessage("success");
mes->SendPicture();
cout << "-------------------------------" << endl;
Messager* mes1 = new MessagerPerfect(new PCMessagerImp);//生成完美版(Perfector)Message,在PC平台下
mes1->Login("xxx", "123");
mes1->SendMessage("success");
mes1->SendPicture();
system("pause");
return 0;
}
有一個
Message
類,有
Login、SendMessage、SendPicture
3種抽象方法,精簡版(Lite)和完美版(Perfector)會對這3種抽象方法進行相應的覆寫(這裡為了友善,隻會對
Perfector
版加入一個播放聲音的操作)。
又在不同的平台(
PC、Mobile
)下,部分操作
PlaySound、DrawShape、WriteText、Connect
不相同(這裡的操作定是和Message類相關,不然就可以把二者獨立開,和Bridge模式便毫無關系)。如下圖所示,就有
兩個不同的次元
。
前面已經說過,
橋模式就是應對這樣多元度的變化
。具體做法就是:
我們通過讓
Message
得到
MessageImp
的指針(多态),這樣,客戶程式就可以組合
Lite、Perfector
和
PC、Mobile
。并且,可以很好的應對未來的擴充,比如
MessageImp
可以擴充一個
Mac
。
注:
Message
和
MessageImp
均是接口。
另外,你在設計時,也許可能會做如下設計:
首先
Message
類,将業務實作方法:
Login、SendMessage、SendPicture
和不同平台下的方法:
PlaySound、DrawShape、WriteText、Connect
均放在這裡。如下
class Messager{
public:
virtual void Login(string username, string password)=0;
virtual void SendMessage(string message)=0;
virtual void SendPicture()=0;
virtual void PlaySound()=0;
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;
virtual ~Messager(){}
};
然後通過繼承的方式來做:
讓
MobileMessage、PCMessage
覆寫不同平台下的方法:
PlaySound、DrawShape、WriteText、Connect
。
接着在
MobilePerfector、MobileLite、PCPerfector、PCPerfector
分别覆寫業務
Login、SendMessage、SendPicture
。
示例圖如下:
假設現在我加一個
Mac
平台,那麼就要增加3個類,如果是10個類呢,就是10*3 = 30個類,而用橋模式隻要10個即可。可以想象這種方法的可擴充性有多差。
3.示例2:圖形和顔色
下面實作在模式動機中給的例子:
圖形形狀和顔色填充
。
直接給代碼:
#include <iostream>
using namespace std;
//實作抽象
class Color
{
public:
virtual void putColor() = 0;
virtual ~Color(){}
};
class RedColor : public Color
{
public:
virtual void putColor()
{
//...
cout << "上紅色" << endl;
//...
}
};
class BullColor : public Color
{
public:
virtual void putColor()
{
//...
cout << "上藍色" << endl;
//...
}
};
class YellowColor : public Color
{
public:
virtual void putColor()
{
//...
cout << "上黃色" << endl;
//...
}
};
class Shape
{
protected:
Color* color;
Shape(Color* _color) :color(_color){}
public:
virtual void drawShape() = 0;
virtual ~Shape(){};
};
class Rectangle : public Shape
{
public:
Rectangle(Color* _color) :Shape(_color){}
virtual void drawShape()
{
cout << "矩形" << "->";
color->putColor();
}
};
class Circle : public Shape
{
public:
Circle(Color* _color) :Shape(_color){}
virtual void drawShape()
{
cout << "圓形" << "->";
color->putColor();
}
};
class Triangle : public Shape
{
public:
Triangle(Color* _color) :Shape(_color){}
virtual void drawShape()
{
cout << "三角形" << "->";
color->putColor();
}
};
int main()
{
Shape* sh = new Rectangle(new BullColor);
sh->drawShape();
sh = new Circle(new YellowColor);
sh->drawShape();
system("pause");
return 0;
}
4.模式定義
注: 什麼叫将抽象和實作分離呢?
- 這裡的抽象指的并
,而是被抽象出來的一套“類庫”,它不是抽象類或者接口
。隻包含骨架代碼,真正的業務邏輯需要委托給定義中的“實作”來完成
- 我們這裡所說的實作也絕非接口的實作類,而
。是一套獨立的“類庫”
- “抽象”和“實作”獨立開發,通過對象之間的組合關系,組裝在一起。
上述描述參考:
https://blog.csdn.net/qq_35423154/article/details/111085839
5.模式結構
Abstraction
就像示例中的
Message
和
Shape
。
Implementor
就像示例中的
MessageImp
和
Color
。
6.要點總結
- Bridge模式使用“對象間的組合關系”解耦了抽象和實作(抽象出骨架代碼,在骨架代碼中某些步驟在實作中完成)之間固有的綁定關系,使得抽象和實作可以沿着各自的次元來變化。所謂抽象和實作沿着各自緯度的變化,即“子類化”它們。
- Bridge模式有時候類似于多繼承方案(就像在示例2中,生成一個紅色矩形,可以看成是同時繼承
類和Shape
類),但是多繼承方案往往違背單一職責原則(即一個類隻有一個變化的原因),複用性比較差。Color
。Bridge模式是比多繼承方案更好的解決方法
- Bridge模式的應用一般在“兩個非常強的變化次元”,有時一個類也有多于兩個的變化次元,這時可以使用Bridge的擴充模式(橋模式就是解決多元度的問題)。