大話設計模式
1 合成/聚合複用原則
概念:盡量使用合成/聚合,盡量不要使用類繼承。【J&DP】
聚合:表示一種弱的“擁有關系”,展現的是A對象可以包含B對象,但B對象不是A對象的一部分;
合成:表示一種強的“擁有關系”,展現了嚴格的部分和整體的關系,部分和整體的聲明周期一樣。
合成/聚合複用原則的好處:優先使用對象的合成/聚合将有助于你保持每個類被封裝,并被集中在單個任務上。這樣的類和類繼承層次保持較小的規模,并且不大可能增長為不可控制的龐然大物。【DP】
繼承的缺點:對象的繼承關系是在編譯時就定義好了,是以無法再運作時改變從父類繼承的實作。子類的實作與它的父類有非常緊密的依賴關系,以至于父類實作中的任何變化會導緻子類發生變化。當你需要複用子類的時候,如果繼承下來的實作不适合解決新的問題,則父類必須重寫或被其它更合适的類替換。這種依賴關系限制了靈活性并最終限制了複用性。
1.2 C++代碼實作
1.2.1 程式結構圖
1.2.2 C++源代碼
HandsetSoft.h類:
#ifndef _HANDSET_SOFT_H_
#define _HANDSET_SOFT_H_
class HandsetSoft
{
public:
virtual void run() = 0;
};
class HandsetGame :public HandsetSoft
{
public:
void run() override;
};
class HandsetAddressedList :public HandsetSoft
{
public:
void run() override;
};
#endif
HandsetSoft.cpp類
#include"HandsetSoft.h"
#include<iostream>
using std::cout;
using std::endl;
void HandsetGame::run()
{
cout << "運作遊戲" << endl;
}
void HandsetAddressedList::run()
{
cout << "運作通訊錄" << endl;
}
HandsetBrand.h類
#ifndef _HANDSET_BRAND_H_
#define _HANDSET_BRAND_H_
class HandsetSoft;
class HandsetBrand
{
protected:
HandsetSoft *soft;//為簡單起見,隻為該品牌手機增加一個功能,實際上可以通過vector/list增加多個軟體
public:
virtual void run() = 0;
void setHandsetSoft(HandsetSoft *soft);
};
class HandsetBrandM:public HandsetBrand
{
public:
void run() override;
};
class HandsetBrandN:public HandsetBrand
{
public:
void run() override;
};
#endif
HandsetBrand.cpp類
#include"HandsetBrand.h"
#include"HandsetSoft.h"
#include<iostream>
using std::cout;
using std::endl;
void HandsetBrand::setHandsetSoft(HandsetSoft *soft)
{
this->soft = soft;
}
void HandsetBrandM::run()
{
cout << "品牌M:";
soft->run();
}
void HandsetBrandN::run()
{
cout << "品牌N:";
soft->run();
}
用戶端Client.cpp
#include"HandsetBrand.h"
#include"HandsetSoft.h"
#include<iostream>
using namespace std;
int main()
{
HandsetSoft *game = new HandsetGame();
HandsetSoft *addressed = new HandsetAddressedList();
HandsetBrand *m = new HandsetBrandM();
HandsetBrand *n = new HandsetBrandN();
m->setHandsetSoft(game);
m->run();
m->setHandsetSoft(addressed);
m->run();
n->setHandsetSoft(game);
n->run();
n->setHandsetSoft(addressed);
n->run();
delete game;
delete addressed;
delete m;
delete n;
system("pause");
return 0;
}
運作結果:
品牌M:運作遊戲
品牌M:運作通訊錄
品牌N:運作遊戲
品牌N:運作通訊錄
請按任意鍵繼續. . .
此時,不管是在增加一個品牌還是增加一個軟體,都隻需增加一個類即可,而不用更改源代碼,滿足封閉-開放原則,而如果單純用繼承的話,不管是手機品牌繼承軟體還是手機軟體繼承品牌,當增加其中一個品牌或者軟體的時候,都需要更改類,不滿足封閉-開放原則。
如按照品牌來分:
按軟體來分:
2 橋接模式
2.1 橋接模式(Bridge)結構圖
2,2 對橋接模式的一些解釋
概念:将抽象部分與它的實作部分分離,使它們都可以獨立地變化【DP】。如上方的手機品牌和手機軟的抽象類聚合。
抽象和它的實作分離并不是說讓抽象類和其他派生類分離,而是值抽象類和它的派生類用來實作自己的對象【DPE】?由于實作的方式有多種(如按軟體分和按手機品牌分),橋接模式的核心意圖就是把這些實作獨立出來,讓它們各自的變化。這使得每種實作的變化不會影響其他的實作,進而達到對應變化的目的。
實作系統可能有多角度分類,每一種分類都有可能變化,那麼就把這種多角度分離出來讓它們獨立變化,減少他們之間的耦合。