設計模式之裝飾者模式

2018-09-19  17:11:22ios

裝飾模式(Decorator Pattern)

  裝飾模式就是在不改變原有類以及不使用繼承的狀況下給原有類動態的增長一些額外的職責。編程

  Tips:不要和建造者模式混淆,建造者模式要求建造的過程是穩定的,可是裝飾者模式這個裝扮的方式並非穩定的,有些裝扮過程甚至無關緊要。例如QQ秀的形象裝扮。(感謝大話設計模式的做者給出如此優秀的實例以理解裝飾模式)設計模式

裝飾模式UML圖

  

Component:定義一個對象方法的虛基類,能夠給這些對象動態的添加職責。 //Component實際上就是須要被裝飾的類的基類架構

ConcreteComponent:定義一個具體的對象,也能夠給這個對象添加一些職責。ide

Decorator:裝飾者基類,它和Component是一種聚合關係,就是說它有一個成員是Component類型的。它繼承了 Component,從外類來擴展Compoment類的功能,但對於Component來講,它是不須要知道Decorator的存在的。spa

ConcreteDecorator:就是具體的裝飾帝鄉,起到給Component添加職責的功能。.net

代碼示例(例子取自大話設計模式)

  解析:這個例子就是模擬了一我的裝扮的過程,首先人有頭、身體、身高、所處背景這四個基本屬性。如今咱們要經過裝飾者模式,給它添加職責,例如給頭帶一個圓帽子、背景設置爲海灘、身高設置爲40四、身體上給穿一套禮服,這個是裝飾過程就是ConcreteDecorator作的事情,那麼具體要裝飾誰呢,要裝飾的對象就是ConcreteComponent。設計

1.Component類指針

#ifndef COMPONENT_H_
#define COMPONENT_H_
#include <string>

class Component
{
public:
    virtual const std::string& getHeadMode() const = 0;
    virtual const std::string& getBodyMode() const = 0;
    virtual const int getHeight() const = 0;
    virtual const std::string& getHairStyle() const = 0;
    virtual const std::string& getName() const = 0;
    virtual void setHeadMode(const std::string strHeadMode) {};
    virtual void setBodyMode(const std::string strBodyMode) {};
    virtual void setHeight(const int iHeight) {};
    virtual void setHairStyle(const std::string strHairStyle){};
    virtual void setName(const std::string strName){};
    Component() = default;
    virtual ~Component() = default;
protected:
    int m_iHeight{0};
    std::string m_strName;
    std::string m_strHeadMode;
    std::string m_strBodyMode;
    std::string m_strHairStyle;
};
#endif
Component

2.具體Component類,這個也是修飾者將要修飾的對象code

#ifndef CONCRETECOMPONENT_H_
#define CONCRETECOMPONENT_H_
#include "Component.h"
#include <string>
class ConcreteComponent:public Component
{
public:
    void setName(const std::string strName)
    {
    m_strName = strName;
    }
    void setHeight(const int iHeight)
    {
    m_iHeight = iHeight;
    }
    void setHeadMode(const std::string strHeadMode)
    {
    m_strHeadMode = strHeadMode;
    }
    void setBodyMode(const std::string strBodyMode)
    {
    m_strBodyMode = strBodyMode;
    }
    void setHairStyle(const std::string strHairStyle)
    {
    m_strHairStyle = strHairStyle;
    }
    const std::string& getHeadMode() const override
    {
    return m_strHeadMode;
    }
    const std::string& getBodyMode() const override
    {
    return m_strBodyMode;
    }
    const int getHeight() const override
    {
    return m_iHeight;
    }
    const std::string& getHairStyle() const
    {
    return m_strHairStyle;
    }
    const std::string& getName() const
    {
    return m_strName;
    }
    ConcreteComponent() = default;
    ~ConcreteComponent() = default;
};
#endif
ConcreteComponent

3.裝飾者基類:從Component繼承而來,並持有一個Component類型的成員指針

#ifndef DECORATOR_H_
#define DECORATOR_H_
#include "Component.h"

class Decorator:public Component
{
public:
    const std::string& getHeadMode() const override
    {
    return m_strHeadMode;
    }
    const std::string& getBodyMode() const override
    {
    return m_strBodyMode;
    }
    const int getHeight() const override
    {
    return m_iHeight;
    } 
    const std::string& getHairStyle() const override
    {
    return m_strHairStyle;
    }
    const std::string& getName() const override
    {
    return m_strName;
    }
    virtual void decorate(Component *) =0;
    virtual void show() = 0;
    Decorator() = default;
    virtual ~Decorator()=default;
protected:
    Component* m_objRole{nullptr};
};
#endif
Decorator

4.具體裝飾者,負責裝飾具體Component類。本例中這個裝飾者負責給小人傳衣服。若是還要裝飾其它的,例如換個髮型,那麼就須要在實現一個新的具體裝飾者(ConcreteDecorator)類,並在客戶端代碼裏調用它的decorate成員進行裝飾。

#ifndef ADDDRESS_H_
#define ADDDRESS_H_
#include "Decorator.h"
#include <iostream>

class AddDress:public Decorator
{
public:
   void decorate(Component *objRole);
   void show();
   AddDress(const std::string strDress):m_strDress(strDress){};
   AddDress() = default;
   ~AddDress() = default;
private:
    std::string m_strDress;
};
#endif

#include "AddDress.h"
void AddDress::decorate(Component* objRole)
{
    m_objRole = objRole;
    if(m_objRole != nullptr)
    {
    std::string strDress = objRole->getBodyMode() + m_strDress;
        objRole->setBodyMode(strDress);
    }
}

void AddDress::show()
{
    if(nullptr != m_objRole)
        std::cout << m_objRole->getName() << "dress a " <<  m_objRole->getBodyMode() << std::endl;
}
AddDress

5.客戶端代碼,使用2和4中的類,對ConcreteComponent進行裝飾。

#include "ConcreteComponent.h"
#include "AddDress.h"

using namespace std;

int main(int argc,char *argv[])
{
    ConcreteComponent objConcreteComponent;
    objConcreteComponent.setName("yang yang");
    objConcreteComponent.setHeight(160);
    
    AddDress objDress("  Skirt");
    objDress.decorate(&objConcreteComponent);
    objDress.show();
    return(1);
}
main

  我以爲使用這個示例來講明裝飾者模式略微有些牽強。

  裝飾模式是爲已有功能動態的添加更多功能的一種方式。當系統須要新功能時,能夠經過向舊的類中添加新代碼(違背了開放-封閉原則),這些新加的代碼一般裝飾了原有類的核心職責或者主要行爲,在主類中增長新的字段,新的方法和新的邏輯,增長了主類的複雜度,而新加入的東西僅僅是爲了知足一些只在某種特定狀況下才會執行的特殊行爲的須要(功能的動態加入和刪除)。針對這種狀況,裝飾模式提供了比繼承更好或者比修改原來相對較好的方式。它把每一個要裝飾的功能放在單獨的類中,並讓這個類包裝它所要裝飾的對象,所以當須要執行特殊行爲時,客戶端代碼就能夠在運行時根據須要有選擇地、按順序的使用裝飾功能包裝對象。因此裝飾模式的優勢就是,把類的裝飾功能從類中搬移去除,這樣能夠簡化原有的類。而且能有效的把類的核心職責和裝飾功能區分開。能夠去除相關類中的重複裝飾邏輯。

裝飾者模式的優缺點

裝飾者模式優缺點部分來自:https://blog.csdn.net/liang19890820/article/details/66973836(還沒實際使用過,但能夠想到它的缺點)

優勢:

  • Decorator 模式與繼承關係的目的都是要擴展對象的功能,可是 Decorator 能夠提供比繼承更多的靈活性。
  • 經過使用不一樣的具體裝飾類以及這些裝飾類的排列組合,能夠創造出不少不一樣行爲的組合。

缺點:

  • 這種比繼承更加靈活機動的特性,也同時意味着更加多的複雜性。
  • 裝飾模式會致使設計中出現許多小類,若是過分使用,會使程序變得很複雜。
  • 裝飾模式是針對抽象構建(Component)類型編程。可是,若是要針對具體構件(ConcreteComponent)編程,應該從新思考應用架構,以及裝飾者是否合適。固然也可改變 Component 接口,增長新的公開的行爲,實現「半透明」的裝飾者模式。在實際項目中要作出最佳選擇。

使用場景:

  • 須要擴展一個類的功能,或給一個類添加附加職責。
  • 須要動態的給一個對象添加功能,這些功能能夠再動態的撤銷。
  • 須要增長由一些基本功能的排列組合而產生的很是大量的功能,從而使繼承關係變的不現實。
  • 當不能採用生成子類的方法進行擴充時。一種狀況是,可能有大量獨立的擴展,爲支持每一種組合將產生大量的子類,使得子類數目呈爆炸性增加。另外一種狀況多是由於類定義被隱藏,或類定義不能用於生成子類。
相關文章
相關標籤/搜索