天天看點

C++實作設計模式——裝飾者(decorator)模式C++實作設計模式——裝飾者(decorator)模式

C++實作設計模式——裝飾者(decorator)模式

  • 裝飾者(decorator)模式定義

  動态地給一個對象添加一些額外的職責。就增加功能來說,Decorator模式相比生成子類更為靈活。不改變接口的前提下,增強所考慮的類的性能。

  • 何時使用

    1)需要擴充一個類的功能,或給一個類增加附加責任。

    2)需要動态的給一個對象增加功能,這些功能可以再動态地撤銷。

    3)需要增加一些基本功能的排列組合而産生的非常大量的功能。

注意:裝飾者模式的根本是裝飾而不是改變接口,原先調用的什麼接口,最後還是會調用到這個接口,也就是裝飾角色的接口與抽象構件角色的接口是完全一緻的,也叫做完全透明裝飾者模式,反之如果接口發生了改變,那就是一種擴充卡了。

舉個通俗的例子:

我們大家都玩遊戲吧,都知道有皮膚這個東西,假設原始角色展示是通過一個show這個接口來展現遊戲角色的,皮膚就是一個裝飾器,那穿戴了皮膚就是調用了裝飾器的show接口,差別在于裝飾器的show裡面比普通的原始的show接口多了添加皮膚的邏輯,裝飾器show在添加了擷取皮膚的邏輯後,最後還是會調用原來的原始show接口進行展示。它的根本還是用原始的show展示角色,沒有改變原來的接口,綜上就是兜兜轉轉還是你的那種感覺。

再給大家舉一個實際中會用到的例子,大家在開發中經常會用到生成日志檔案吧,而往往不同的場合會生成不同格式的日志内容,比如有json的,xml的,表格的各種形式,如果用繼承的方式就需要在列印日志的類下不停的派生各種子類,然後重載日志輸出接口,這樣類的複雜度越來越高。此時如果用裝飾者,可以需要什麼模式的時候就裝飾什麼。代碼如下:

#include<iostream>
using namespace std;

class log {          //整個日志類
    public:
        virtual void log_out(string filename, string  value) {
            cout<<"輸出日志"<<value<<"到"<<filename<<"檔案"<<endl;
        }
};

class errlog:public log {    //錯誤日志輸出類
    public:
    void log_out(string filename, string  value) {
            cout<<"輸出錯誤日志"<<value<<"到"<<filename<<"檔案"<<endl;
        }
};

class debuglog:public log {  //debug日志輸出類
    public:
    void log_out(string filename, string  value) {
            cout<<"輸出debug日志"<<value<<"到"<<filename<<"檔案"<<endl;
        }
}; 

class decoratorlog:public log {//日志輸出裝飾器
    public:
        log *m_logout;
        decoratorlog() {}
        decoratorlog(log *logout) {
            this->m_logout = logout;
        }
        void log_out(string filename, string  value) {
                cout<<"輸出debug日志"<<value<<"到"<<filename<<"檔案"<<endl;
        }
};

class jsondecorator:public decoratorlog {//json日志輸出裝飾器
    public:
        jsondecorator(log *logout) {
            this->m_logout = logout;
        }
        void log_out(string filename, string  value) {
            cout<<"value進行了json轉換"<<endl;     //裝飾器的作用,也就是需要擴充的新功能需求
            m_logout->log_out(filename,value);    //調用到原先的接口
        }
};

class xmldecorator:public decoratorlog {//json日志輸出裝飾器
    public:
        xmldecorator(log *logout) {
            this->m_logout = logout;
        }
        void log_out(string filename, string  value) {
            cout<<"value進行了xml轉換"<<endl;      //裝飾器的作用,也就是需要擴充的新功能需求
            m_logout->log_out(filename,value);    //調用到原先的接口
        }
};
int main() {
    log *log1 = new jsondecorator( new debuglog());
    log1->log_out("1.json","hello");
    log *log2 = new xmldecorator( new errlog());
    log2->log_out("1.xml","world");
    return 0;
}

/*
value進行了json轉換
輸出debug日志hello到1.json檔案
value進行了xml轉換
輸出錯誤日志world到1.xml檔案
*/
           
C++實作設計模式——裝飾者(decorator)模式C++實作設計模式——裝飾者(decorator)模式

這個模式的思想就是,裝飾者就隻是裝飾,無論用到哪個裝飾器子類,最後還是會調用到實際的log_out接口函數。

  • 裝飾者模式的結構
C++實作設計模式——裝飾者(decorator)模式C++實作設計模式——裝飾者(decorator)模式

繼續閱讀