在做面向對象的軟件開發時我們往往想達到更高的代碼可複用性和更合理的軟件顆粒度。
根據《設計模式——可複用面向對象軟件的基礎》所說:“你必須找到相關的對象,以適當的顆粒度將他們迴歸類,再定義類的接口和繼承層次,建立對象之間的基本關係。你的設計應該對手頭的問題有針對性,同時對將來的問題和需求也要有足夠的通用性。”
內行的設計者知道:不是解決任何問題都要從頭做起。他們更願意複用以前使用的解決方案。這些重複的模式方案解決特定的問題,使得面向對象的設計更靈活、優雅,最終複用性更好。它們幫助設計者將新的設計建立在以往的工作基礎上,複用以往的成功設計方案。一個熟悉這些設計模式的設計者不需要再去發現它們,而能夠立即將他們應用於設計問題中。
本系列文章主要參考文獻爲——設計模式,可複用面向對象軟件的基礎(Design Patterns Elements of Reusable Object-Oriented SoftWare Erich.),內部代碼基本用C++語言編寫。
彙總鏈接:23種設計模式C++實現——概要(索引彙總)
摘要
本章主要說明裝飾者模式,該設計模式主要意圖是:動態的給一些對象添加一些額外的職責,相比於繼承子類更加靈活。
有的時候我們想給某個對象增加一些功能(而不是給整個類增加功能,不需要通過定義子類添加新的類實現),例如一個普通滑塊增加立體效果,在一個普通樣式增加花紋。
具體實現下邊我們就通過一個小栗子來說明什麼是裝飾者模式。
主要參與者
該設計模式的參與者有5個,分別是:
- Virtual Component 抽象對象的接口,可以給這些對象動態的添加職責
- Concrete Component 實例對象,可以給這個對象增加一些職責
- Virtual Decorator 維持一個指向Component對象的指針,並定義與Component接口一致的接口
- Concrete Decorator 具體向組件添加職責
- Client 用戶
優點
具體實現代碼
例子中Cake是抽象雞蛋灌餅接口,OriginalCake是不加任何配料的原味雞蛋灌餅,Decorator是抽象裝飾器,EggAddCake 是給當前餅再加一個雞蛋,SausageAddCake 是給當前餅再加一個香腸,我們在買雞蛋灌餅時可以選擇什麼都不加,或加一個蛋,加多個蛋,加腸,加多個腸,同時加蛋和腸的情況,如果使用繼承的方式實現上述操作可能會造成產生很多類且比較死板,比如說加蛋一個類,加腸一個類,同時加蛋和腸一個類,如果有其他配菜則會更加複雜,而使用裝飾者模式則是在原有實例對象的基礎上增加修飾,接下來我們通過一個實例代碼來說明具體實現:
對象的接口(Component )
/****************************************************************
Author : BingLee
Date : 2019-08-07
Info :
https://blog.csdn.net/Bing_Lee (C)All rights reserved.
******************************************************************/
#ifndef CAKE_H
#define CAKE_H
#include <stdio.h>
class Cake
{
public:
virtual void Info() = 0;
virtual float Price() = 0;
};
class OriginalCake : public Cake
{
public:
OriginalCake(){}
void Info(){printf("Original test cake. ");}
float Price(){return 3.0;} //base price
};
#endif // CAKE_H
裝飾器的接口(Decorator)
/****************************************************************
Author : BingLee
Date : 2019-08-07
Info :
https://blog.csdn.net/Bing_Lee (C)All rights reserved.
******************************************************************/
#ifndef DECORATOR_H
#define DECORATOR_H
#include "cake.h"
class Decorator : public Cake
{
public:
Decorator(Cake *cake = 0){
this->Init(cake);
}
void Init(Cake *cake){
if(0 == cake)
this->m_cake = new OriginalCake;
else
this->m_cake = cake;
}
virtual void Info(){m_cake->Info();}
virtual float Price(){return m_cake->Price();}
protected:
Cake *m_cake;
};
class EggAddCake : public Decorator
{
public:
EggAddCake(Cake *cake = 0){Init(cake);}
void Info(){
m_cake->Info();
printf("Add Egg. ");}
float Price(){return m_cake->Price() + 1.5;}
};
class SausageAddCake : public Decorator
{
public:
SausageAddCake(Cake *cake = 0){Init(cake);}
void Info(){
m_cake->Info();
printf("Add Sausage. ");}
float Price(){return m_cake->Price() + 2.0;}
};
#endif // DECORATOR_H
用戶(Client)
#include <QCoreApplication>
#include "cake.h"
#include "decorator.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//原味雞蛋灌餅
OriginalCake *originalCake = new OriginalCake;
originalCake->Info();
printf("\n Price %.2f\n",originalCake->Price());
//加蛋雞蛋灌餅
EggAddCake *eggAddCake = new EggAddCake(new OriginalCake);
eggAddCake->Info();
printf("\n Price %.2f\n",eggAddCake->Price());
//加蛋加腸雞蛋灌餅
SausageAddCake *sausageAddCake = new SausageAddCake(new EggAddCake(new OriginalCake));
sausageAddCake->Info();
printf("\n Price %.2f\n",sausageAddCake->Price());
//加腸雞蛋灌餅
SausageAddCake *sausageAddCake1 = new SausageAddCake();
sausageAddCake1->Info();
printf("\n Price %.2f\n",sausageAddCake1->Price());
return a.exec();
}
輸出結果
補充說明
本篇博客中的代碼均已通過編譯,如有Bug,請提出寶貴意見~