在做面向對象的軟件開發時我們往往想達到更高的代碼可複用性和更合理的軟件顆粒度。
根據《設計模式——可複用面向對象軟件的基礎》所說:“你必須找到相關的對象,以適當的顆粒度將他們迴歸類,再定義類的接口和繼承層次,建立對象之間的基本關係。你的設計應該對手頭的問題有針對性,同時對將來的問題和需求也要有足夠的通用性。”
內行的設計者知道:不是解決任何問題都要從頭做起。他們更願意複用以前使用的解決方案。這些重複的模式方案解決特定的問題,使得面向對象的設計更靈活、優雅,最終複用性更好。它們幫助設計者將新的設計建立在以往的工作基礎上,複用以往的成功設計方案。一個熟悉這些設計模式的設計者不需要再去發現它們,而能夠立即將他們應用於設計問題中。
本系列文章主要參考文獻爲——設計模式,可複用面向對象軟件的基礎(Design Patterns Elements of Reusable Object-Oriented SoftWare Erich.),內部代碼基本用C++語言編寫。
彙總鏈接:23種設計模式C++實現——概要(索引彙總)
摘要
本章主要說明外觀模式,該設計模式主要意圖是:將一個具有統一特徵流程性的東西封裝成爲一個外部接口,外部接口不需要了解內部實現,只需要調用接口,其餘操作由接口函數內部完成。
我們的產品有普通用戶,也有專業用戶,對於普通用戶我們要提供給他儘量簡單的使用方式,對專業用戶他們可能會針對其中某一環節的結果做修改,那麼這種簡單自動流程接口與細節函數接口同時存在的情況就是外觀模式。
具體實現下邊我們就通過一個小栗子來說明什麼是外觀模式。
主要參與者
該設計模式的參與者有5個,分別是:
- Facade (ShishKebab) 分配用戶請求給適當的子系統對象
- Subsystem classes(ChoppedLamb, PickledLamb, BarbecueBraze, LambWithBarbecueBrazeObj, FinishedShishKebab)實現子系統的功能,處理由Facade 分配的任務,沒有Facade 的任何相關信息
- Client 用戶
優點
- 對客戶屏蔽了系統組件,減少客戶處理對象的數目並且使得系統使用更簡單
- 實現了子系統與客戶之間的鬆耦合關係,而子系統內部是緊耦合的,有助於建立層次結構系統,也有助於對象之間的依賴關係分層
- 雖然包裝了一層,但並不限制使用子系統的類
具體實現代碼
例子中Cake是抽象雞蛋灌餅接口,OriginalCake是不加任何配料的原味雞蛋灌餅,Decorator是抽象裝飾器,EggAddCake 是給當前餅再加一個雞蛋,SausageAddCake 是給當前餅再加一個香腸,我們在買雞蛋灌餅時可以選擇什麼都不加,或加一個蛋,加多個蛋,加腸,加多個腸,同時加蛋和腸的情況,如果使用繼承的方式實現上述操作可能會造成產生很多類且比較死板,比如說加蛋一個類,加腸一個類,同時加蛋和腸一個類,如果有其他配菜則會更加複雜,而使用裝飾者模式則是在原有實例對象的基礎上增加修飾,接下來我們通過一個實例代碼來說明具體實現:
對象的接口(Component )
/****************************************************************
Author : BingLee
Date : 2019-08-12
Info :
https://blog.csdn.net/Bing_Lee (C)All rights reserved.
******************************************************************/
#ifndef SHISHKEBAB_H
#define SHISHKEBAB_H
#include <stdio.h>
class ChoppedLamb //羊肉原料
{
public:
ChoppedLamb(){printf("Original chopped lamb row.\n");}
};
class PickledLamb //醃羊肉
{
public:
PickledLamb(ChoppedLamb *choppedLamb = 0)
:m_choppedLamb(choppedLamb){}
void ProcessLamb(){printf("Pickled Lamb.\n");}
protected:
ChoppedLamb *m_choppedLamb;
};
class BarbecueBraze //烤肉釺子
{
public:
BarbecueBraze(){}
void Wash(){printf("Clean Barbecue Braze.\n");}
};
class LambWithBarbecueBrazeObj //穿好的烤肉串
{
public:
LambWithBarbecueBrazeObj(PickledLamb *pickledLamb = 0, BarbecueBraze *barbecueBraze = 0)
:m_barbecueBraze(barbecueBraze),
m_pickledLamb(pickledLamb){}
void ProcessShishKebabObj(){printf("Skew the lamb with BarbecueBraze.\n");}
protected:
BarbecueBraze *m_barbecueBraze;
PickledLamb *m_pickledLamb;
};
class FinishedShishKebab //烤好的羊肉
{
public:
FinishedShishKebab(LambWithBarbecueBrazeObj *obj)
:m_lambWithBarbecueBrazeObj(obj){}
void Info(){printf("Got Finished Shish Kebab.\n");}
protected:
LambWithBarbecueBrazeObj *m_lambWithBarbecueBrazeObj;
};
class ShishKebab //烤羊肉
{
public:
ShishKebab(){}
void ProcessBarbecue(ChoppedLamb *inPut, FinishedShishKebab *outPut){
PickledLamb *pickledLamb = new PickledLamb(inPut);
BarbecueBraze *barbecueBraze = new BarbecueBraze;
barbecueBraze->Wash();
LambWithBarbecueBrazeObj *lambWithBarbecueBrazeObj =
new LambWithBarbecueBrazeObj(pickledLamb,barbecueBraze);
lambWithBarbecueBrazeObj->ProcessShishKebabObj();
FinishedShishKebab *finishedShishKebab = new FinishedShishKebab(lambWithBarbecueBrazeObj);
outPut = finishedShishKebab;
printf("Barbecue the ShishKebabObj.\n");}
};
#endif // SHISHKEBAB_H
用戶(Client)
//Common User
#include <QCoreApplication>
#include "shishkebab.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//first: use Facade patten
printf(" Facade patten.\n");
ChoppedLamb *row = new ChoppedLamb;
FinishedShishKebab *product;
ShishKebab *shishKebab = new ShishKebab();
shishKebab->ProcessBarbecue(row, product);
product->Info();
return a.exec();
}
輸出結果:
//professional User
#include <QCoreApplication>
#include "shishkebab.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
printf("\n Standard way.\n");
ChoppedLamb *row1 = new ChoppedLamb;
PickledLamb *pickledLamb = new PickledLamb(row1);
BarbecueBraze *barbecueBraze = new BarbecueBraze;
barbecueBraze->Wash();
LambWithBarbecueBrazeObj *lambWithBarbecueBrazeObj =
new LambWithBarbecueBrazeObj(pickledLamb,barbecueBraze);
lambWithBarbecueBrazeObj->ProcessShishKebabObj();
FinishedShishKebab *finishedShishKebab = new FinishedShishKebab(lambWithBarbecueBrazeObj);
finishedShishKebab->Info();
return a.exec();
}
輸出結果:
補充說明
該模式的思想是給外部客戶儘量簡單的使用接口,對下層子系統實現的流程進行封裝,但同時又不限制用戶對下層子系統類的使用
本篇博客中的代碼均已通過編譯,如有Bug,請提出寶貴意見~