天天看點

設計模式學習筆記--橋接模式一.簡介二.橋接模式的例子三.橋接模式的總結

一.簡介

今天來學習一下23種設計模式中的橋接模式。我們再設計系統時,如果某個類存在兩個獨立變化的次元,一種方案是使用多層繼承,如果第一個次元有A個分支,第二個次元有B個分支的話,那麼總共我們需要A*B個子類才能實作,這将是一個非常龐大的繼承樹。如果第一個次元增加了一個分支,那麼我們需要再增加B個子類,擴充也變得很麻煩。而第二種方式就是我們今天要學習的橋接模式,通過橋接模式,我們可以将兩個次元分離出來,使兩者獨立擴充,成為兩個獨立的繼承樹,并在最上層的抽象層中建立一個關聯,這個關聯就類似于連接配接兩個獨立結構的橋,是以我們稱之為橋接模式。 下面我們看一下橋接模式的定義以及橋接模式的UML類圖: 橋接模式(Bridge Pattern):将抽象部分與它的實作部分分離,使它們都可以獨立地變化。它是一種對象結構型模式,又稱為柄體(Handle and Body)模式或接口(Interface)模式。

設計模式學習筆記--橋接模式一.簡介二.橋接模式的例子三.橋接模式的總結

簡單解釋一下橋接模式的UML類圖,整體的繼承樹被拆分成兩組繼承樹,以Abstraction為根的繼承樹和以Implementor為根的繼承樹。Abstraction通過一個抽象的接口調用Implementor,我們可以将Implementor的子類對象注入到Abstraction子類對象中,通過聚合的方式達到想要的效果。

二.橋接模式的例子

我們通過一個例子來看一下橋接模式的應用。我們現在要設計一個小遊戲,包含幾個兵種,男刀客,女刀客,男槍手,女槍手。怎麼樣設計這個人物的結構體系呢?我們分别看一下多層繼承的情況和橋接模式的情況。

1.多層繼承的情況

// Design Pattern.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
using namespace std;

//人物基類
class Character
{
public:
	virtual void Attack() = 0;
};

//男人物
class MaleCharacter : public Character
{
public:
	virtual void Attack() = 0;
};

//女人物
class FemaleCharacter : public Character
{
public:
	virtual void Attack() = 0;
};

//男刀客
class PhysicalMaleChar : public MaleCharacter
{
public:
	virtual void Attack()
	{
		cout << "男角色: 實體攻擊" << endl;
	}
};

//女刀客
class PhysicalFemaleChar : public FemaleCharacter
{
public:
	virtual void Attack()
	{
		cout << "女角色: 實體攻擊" << endl;
	}
};

//男法師
class MagicMaleChar : public MaleCharacter
{
public:
	virtual void Attack()
	{
		cout << "男角色: 法術攻擊" << endl;
	}
};

//女法師
class MagicFemalChar : public FemaleCharacter
{
public:
	virtual void Attack()
	{
		cout << "女角色: 法術攻擊" << endl;
	}
};

int _tmain(int argc, _TCHAR* argv[])
{
	
	Character* character = new MagicFemalChar();
	character->Attack();

	system("pause");
	

	return 0;
}
           

結果: 女角色: 法術攻擊

請按任意鍵繼續. . .

恩,雖然實作了想要的功能,不過如果我們的職業增加了幾個,那麼我們就要給每個新增的職業建立兩個類,很麻煩。還是看看使用橋接模式的情況吧。

2.橋接模式的情況

// Design Pattern.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
using namespace std;

//屬性基類,相當于Implement類
class Attribute
{
public:
	virtual void Attack() = 0;
};

//人物基類,相當于UML圖中的Abstract類
class Character
{
protected:
	//儲存一個屬性的指針
	Attribute* m_Attribute;
public:
	//設定屬性(職業)
	void SetAttribute(Attribute* attribute)
	{
		m_Attribute = attribute;
	}
	//攻擊接口
	virtual void Attack() = 0;
};

//男人物
class MaleCharacter : public Character
{
public:
	virtual void Attack() override
	{
		cout << "男角色: ";
		m_Attribute->Attack();
	}
};

//女人物
class FemaleCharacter : public Character
{
public:
	virtual void Attack() override
	{
		cout << "女角色: ";
		m_Attribute->Attack();
	}
};

//實體屬性
class PhysicalAttribute : public Attribute
{
public:
	void Attack() override
	{
		cout << "實體攻擊" << endl;
	}
};

//法系屬性
class MagicAttribute : public Attribute
{
public:
	void Attack() override
	{
		cout << "法系攻擊" << endl;
	}
};





int _tmain(int argc, _TCHAR* argv[])
{
	
	Character* character = new FemaleCharacter();
	Attribute* magicAttribute = new MagicAttribute();
	character->SetAttribute(magicAttribute);
	character->Attack();

	system("pause");
	

	return 0;
}
           

結果: 女角色: 法系攻擊

請按任意鍵繼續. . .

我們使用了橋接模式,将人物性别和人物攻擊的屬性作為兩個不同的屬性,拆分成兩個不同的繼承樹,然後在人物基類中儲存一個人物屬性的指針,使二者行程了聚合關系。這樣,我們減少了備援的類,大大減少了繼承的複雜度,增強了複用性。在增加新類或者屬性時,隻需要增加新的屬性類即可,符合開放-封閉原則。

三.橋接模式的總結

最後,我們來總結一下橋接模式的優點缺點以及使用時機。

優點: 1)橋接模式是多層繼承體系的一個很好的代替解決方案,大大減少了子類的個數,增加了複用性。 2)橋接模式分離了抽象接口以及實作部分,采用聚合方式,解耦了抽象和實作之間固有的綁定關系,讓抽象和實作在不同的繼承體系中實作。 3)橋接模式很好地提高了系統的擴充性,在擴充兩個次元中任意一個次元時,都不需要修改原有内容,符合開放-封閉原則。

缺點: 1)橋接模式增加了系統的了解的難度,不如多層繼承來得直接。 2)如何識别并分離兩個次元比較困難,是以使用有一定的局限性。

使用時機: 如果我們的系統之前是使用多層繼承方式實作的,在兩個層次之間靜态的繼承關系不夠靈活時,我們就可以考慮橋接模式。當我們的系統中存在兩個或多個獨立變化的次元,這兩個次元都需要獨立擴充,為了不讓擴充的複雜度變成M*N,而是M+N的話,我們就可以使用橋接模式。

繼續閱讀