设计模式——装饰器模式
文章目錄
- 一、基本知識
- 1.定義
- 2.背景示例
- 3.要點
- 二、結構圖
- 三、實例說明
- 1.普通代碼
- 2.裝飾器模式代碼
一、基本知識
在我第一次接觸裝飾器模式的時候,將它和責任鏈模式分不開,但是事實上它們是有區別的。
1.定義
動態地給一個對象增加一些額外的職責。就增加功能而言,裝飾器模式比生產子類更為靈活。
2.背景示例
普通員工有銷售獎金,累計獎金,部門經理除此之外還有團隊獎金;后面可能會添加環比增長獎金,同時可能針對不同的職位產生不同的獎金組合。
3.要點
①通過采用組合而非繼承的手法, 裝飾器模式實現了在運行時動態擴展對象功能的能力,而且可以根據需要擴展多個功能。 避免了使用繼承帶來的“靈活性差”和“多子類衍生問題”。
②不是解決“多子類衍生問題”問題,而是解決“父類在多個方向上的擴展功能”問題。
③裝飾器模式把一系列復雜的功能分散到每個裝飾器當中,一般一個裝飾器只實現一個功能,實現復用裝飾器的功能。
二、結構圖
對于本人來說,先看結構圖的話,看不懂,都是先看示例代碼,回頭來再看結構圖才看得懂。
三、實例說明
1.普通代碼
#include<iostream> #include<string> using namespace std;// 普通員工有銷售獎金,累計獎金,部門經理除此之外還有團隊獎金;后面可能會添加環比增長獎金,同時可能產生不同的獎金組合; // 銷售獎金 = 當月銷售額 * 4% // 累計獎金 = 總的回款額 * 2% // 部門獎金 = 團隊銷售額 * 1% // 環比獎金 = (當月銷售額-上月銷售額) * 1% // 銷售后面的參數可能會調整 class Context { public:bool isMgr;string name;double groupsale; };class Bonus { public:double CalcBonus(Context& ctx) {double bonus = 0.0;bonus += CalcMonthBonus(ctx);bonus += CalcSumBonus(ctx);if (ctx.isMgr) {bonus += CalcGroupBonus(ctx);}return bonus;} private:double CalcMonthBonus(Context& ctx) {double bonus;/*一系列操作求銷售獎金*/return bonus;}double CalcSumBonus(Context& ctx) {double bonus;/*一系列操作求總的回款額*/return bonus;}double CalcGroupBonus(Context& ctx) {double bonus;/*一系列操作求部門獎金*/return bonus;} };int main() {Context ctx;// 設置 ctxBonus* bonus = new Bonus;bonus->CalcBonus(ctx); }2.裝飾器模式代碼
#include <iostream> #include <string> // 普通員工有銷售獎金,累計獎金,部門經理除此之外還有團隊獎金;后面可能會添加環比增長獎金,同時可能產生不同的獎金組合; // 銷售獎金 = 當月銷售額 * 4% // 累計獎金 = 總的回款額 * 0.2% // 部門獎金 = 團隊銷售額 * 1% // 環比獎金 = (當月銷售額-上月銷售額) * 1% // 銷售后面的參數可能會調整 using namespace std; class Context { public:bool isMgr;string name;double groupsale; };// 試著從職責出發,將職責抽象出來 class CalcBonus { public:CalcBonus(CalcBonus * c = nullptr) : cc(c) {}virtual double Calc(Context &ctx) {return 0.0; // 基本工資}virtual ~CalcBonus() {}protected:CalcBonus* cc;//通過組合的方式 };class CalcMonthBonus : public CalcBonus { public:CalcMonthBonus(CalcBonus * c) : CalcBonus(c) {}virtual double Calc(Context &ctx) {double mbonus;/*求銷售獎金操作*/return mbonus + cc->Calc(ctx);} };class CalcSumBonus : public CalcBonus { public:CalcSumBonus(CalcBonus * c) : CalcBonus(c) {}virtual double Calc(Context &ctx) {double sbonus;/*求累計獎金操作*/return sbonus + cc->Calc(ctx);} };class CalcGroupBonus : public CalcBonus { public:CalcGroupBonus(CalcBonus * c) : CalcBonus(c) {}virtual double Calc(Context &ctx) {double gbnonus;/*求部門獎金操作*/return gbnonus + cc->Calc(ctx);} };class CalcCycleBonus : public CalcBonus { public:CalcCycleBonus(CalcBonus * c) : CalcBonus(c) {}virtual double Calc(Context &ctx) {double gbnonus ;/*求環比獎金操作*/return gbnonus + cc->Calc(ctx);} };int main() {// 1. 普通員工Context ctx1;ctx1.isMgr = false;CalcBonus *base = new CalcBonus();CalcBonus *cb1 = new CalcSumBonus(base);CalcBonus *cb2 = new CalcMonthBonus(cb1);cb2->Calc(ctx1);//普通員工獎金只求銷售獎金和部門獎金// 2. 部門經理Context ctx2;ctx2.isMgr = true;CalcBonus *cb3 = new CalcGroupBonus(cb2);cb3->Calc(ctx2);//部門獎金求銷售、累計、部門獎金(環比獎金暫時沒有設置) }可以看見,裝飾器和責任鏈最大的區別是裝飾器模式是最主要的是組合手法。而責任鏈是繼承,然后每個子類的實例之間通過鏈表的方式低度耦合。裝飾器之所以采用組合,是因為子類并不只是其中一個子類符合條件進行操作,而是多個子類都要操作,比如獎金,是通過多個子類求出來的。
而責任鏈模式通常是某個子類來解決這個事情,而鏈表是通常按照一定的先后順序將子類低度耦合起來,有事件要處理時,通過鏈表遍歷這個鏈表上的類,找到適合處理這個事情的類,這個往往是一個類就可以處理完。
當然,其實大部分可以用裝飾器模式的很可能也可以用責任鏈模式,因為責任鏈模式只是往往一個事件只需要一個類處理,但是也可以是多個類都要處理,但是通過執行先后順序將類用鏈表連接起來,就像是一個工廠的流水線一樣。
總結
以上是生活随笔為你收集整理的设计模式——装饰器模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 设计模式——责任链模式
- 下一篇: 设计模式——模板方法