天天看點

設計模式之橋模式(Bridge)前言Bridge設計模式

目錄

  • 前言
  • Bridge設計模式
    • 1.模式動機
    • 2.示例1
    • 3.示例2:圖形和顔色
    • 4.模式定義
    • 5.模式結構
    • 6.要點總結

前言

在學習侯捷老師的有關設計模式的課程(李建忠老師主講)中,老師對23種設計模式的有自己的劃分,如下。是以老師講解是按照這種順序講解。

設計模式之橋模式(Bridge)前言Bridge設計模式

單一職責:

設計模式之橋模式(Bridge)前言Bridge設計模式

Bridge設計模式

1.模式動機

由于某些類型的固有的實作邏輯,使得它們具有兩個變化的次元,乃至多個緯度的變化。

是以Bridge模式的動機就是應對“

多元度的變化

”。

看文字描述表枯燥,下面舉幾個例子:

  1. 商城系統中的電腦分類:如

    電腦類型+電腦品牌

    ,這是兩個次元的變化。
    設計模式之橋模式(Bridge)前言Bridge設計模式
  2. 圖形形狀+顔色填充

    兩種變化的次元
    設計模式之橋模式(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模式便毫無關系)。如下圖所示,就有

兩個不同的次元

設計模式之橋模式(Bridge)前言Bridge設計模式

前面已經說過,

橋模式就是應對這樣多元度的變化

。具體做法就是:

我們通過讓

Message

得到

MessageImp

的指針(多态),這樣,客戶程式就可以組合

Lite、Perfector

PC、Mobile

。并且,可以很好的應對未來的擴充,比如

MessageImp

可以擴充一個

Mac

注:

Message

MessageImp

均是接口。

設計模式之橋模式(Bridge)前言Bridge設計模式

另外,你在設計時,也許可能會做如下設計:

首先

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

示例圖如下:

設計模式之橋模式(Bridge)前言Bridge設計模式

假設現在我加一個

Mac

平台,那麼就要增加3個類,如果是10個類呢,就是10*3 = 30個類,而用橋模式隻要10個即可。可以想象這種方法的可擴充性有多差。

3.示例2:圖形和顔色

下面實作在模式動機中給的例子:

圖形形狀和顔色填充

設計模式之橋模式(Bridge)前言Bridge設計模式

直接給代碼:

#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.模式定義

設計模式之橋模式(Bridge)前言Bridge設計模式

注: 什麼叫将抽象和實作分離呢?

  • 這裡的抽象指的并

    不是抽象類或者接口

    ,而是被抽象出來的一套“類庫”,它

    隻包含骨架代碼,真正的業務邏輯需要委托給定義中的“實作”來完成

  • 我們這裡所說的實作也絕非接口的實作類,而

    是一套獨立的“類庫”

  • “抽象”和“實作”獨立開發,通過對象之間的組合關系,組裝在一起。

上述描述參考:

https://blog.csdn.net/qq_35423154/article/details/111085839

5.模式結構

設計模式之橋模式(Bridge)前言Bridge設計模式

Abstraction

就像示例中的

Message

Shape

Implementor

就像示例中的

MessageImp

Color

6.要點總結

  • Bridge模式使用“對象間的組合關系”解耦了抽象和實作(抽象出骨架代碼,在骨架代碼中某些步驟在實作中完成)之間固有的綁定關系,使得抽象和實作可以沿着各自的次元來變化。所謂抽象和實作沿着各自緯度的變化,即“子類化”它們。
  • Bridge模式有時候類似于多繼承方案(就像在示例2中,生成一個紅色矩形,可以看成是同時繼承

    Shape

    類和

    Color

    類),但是多繼承方案往往違背單一職責原則(即一個類隻有一個變化的原因),複用性比較差。

    Bridge模式是比多繼承方案更好的解決方法

  • Bridge模式的應用一般在“兩個非常強的變化次元”,有時一個類也有多于兩個的變化次元,這時可以使用Bridge的擴充模式(橋模式就是解決多元度的問題)。

繼續閱讀