天天看點

C++設計模式2——裝飾者模式

目錄

1.導讀

2.裝飾者模式介紹

3.代碼執行個體

3.1 以學習英雄的技能為例

3.2 以更換英雄的皮膚為例

1.導讀

大家好,首先我們來看兩個圖,下面兩個圖想必很多人都認識吧,不認識也沒關系,後面告訴你!

這是我最喜歡的射手-薇恩

C++設計模式2——裝飾者模式

這是打野的信仰-盲僧

C++設計模式2——裝飾者模式

好了,圖随便看下就可以了,你以為我真的要跟你們講英雄聯盟嗎,别逗了,我不敢!不廢話了,其實今天,我是打算以英雄聯盟為例,給大家分享一下關于“裝飾者模式”的知識。

玩過英雄聯盟的應該都知道,聯盟的每個英雄基本上都有皮膚,人氣高的英雄皮膚會特别多,每個個皮膚,都是英雄的一種妝扮,可以簡單地了解為是一套衣服。我們把這個英雄的皮膚和“裝飾者模式”聯系起來看的話,那麼一個英雄可以當成是被裝飾的對象,而不同的皮膚,就是進行不同裝飾後的樣子。

每個英雄都還有四個技能,玩家釋放技能的時候,一般都是按QWER,四個按鍵對應四個技能。每個技能其實也可以看成是英雄的一種裝飾,不過與皮膚不同的是,遊戲規定一個英雄在同一局遊戲裡面隻能使用一種皮膚,但是在一局遊戲裡面,英雄會同時擁有四個技能。

在文中,我将分别以技能和皮膚為例,編寫兩段代碼,來深入地了解一下“裝飾者模式”的運用。

2.裝飾者模式介紹

概念:裝飾器模式(Decorator Pattern)允許向一個現有的對象添加新的功能,同時又不改變其結構。這種類型的設計模式屬于結構型模式,它是作為現有的類的一個包裝。這種模式建立了一個裝飾類,用來包裝原有的類,并在保持類方法簽名完整性的前提下,提供了額外的功能。

何時使用:一般的,我們為了擴充一個類經常使用繼承方式實作,但是随着繼承層次的增加和擴充功能的增多,子類會很膨脹。如果希望在不增加很多子類的情況下擴充類的功能,那麼就可以使用裝飾者模式,動态地給一個對象添加一些額外的職責。

如何使用:将具體功能職責劃分,讓每個職能繼承裝飾者基類。

優點:裝飾類和被裝飾類可以獨立發展,不會互相耦合,裝飾模式是繼承的一個替代模式,裝飾模式可以動态擴充一個實作類的功能。

缺點:多層裝飾比較複雜,可能會增加代碼量

3.代碼執行個體

3.1 以學習英雄的技能為例

#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;

//英雄接口 
class Hero 
{
public:
    //換皮膚
    virtual void ChangeSkin() = 0;
};

//ConcreteComponent 具體英雄盲僧
class Mangseng : public Hero
{
protected:
    string name;

public:
    Mangseng(string name)
    {
        this->name = name;
    }

    void ChangeSkin()
    {
        cout << name;
    }
};

//裝飾者基類——皮膚類
class Skin : public Hero {

    //持有一個英雄對象接口
protected:
    Hero *m_pHero;

public:
    Skin(Hero *pHero)
    {
        this->m_pHero = pHero;
    }

    void ChangeSkin()
    {
        if (m_pHero != NULL)
            m_pHero->ChangeSkin();
    }
};

//盲僧皮膚之"龍的傳人"
class Skin_LegendOfDragon : public Skin
{
private:
    string m_strSkinName;

public:
    Skin_LegendOfDragon(Hero *pHero, string strSkinName) :Skin(pHero)
    {
        this->m_strSkinName = strSkinName;
    }

    void ChangeSkin()
    {
        m_pHero->ChangeSkin();
        cout << "換上了新皮膚:" << m_strSkinName << endl;
    }
};

//盲僧皮膚之"泳池派對"
class Skin_PoolParty : public Skin
{
private:
    string m_strSkinName;

public:
    Skin_PoolParty(Hero *pHero, string strSkinName) :Skin(pHero)
    {
        this->m_strSkinName = strSkinName;
    }

    void ChangeSkin()
    {
        m_pHero->ChangeSkin();
        cout << "換上了新皮膚:" << m_strSkinName << endl;
    }
};

//盲僧皮膚之"SKT T1冠軍皮膚"
class Skin_SKT : public Skin
{
private:
    string m_strSkinName;

public:
    Skin_SKT(Hero *pHero, string strSkinName) :Skin(pHero)
    {
        this->m_strSkinName = strSkinName;
    }

    void ChangeSkin()
    {
        m_pHero->ChangeSkin();
        cout << "換上了新皮膚:" << m_strSkinName << endl;
    }
};


int main()
{
    Mangseng objMs("盲僧");
    Skin_SKT skt(&objMs, "SKT T1冠軍皮膚");
    Skin_PoolParty poolParty(&objMs, "泳池派對");
    Skin_LegendOfDragon dragon(&objMs, "龍的傳人");
    skt.ChangeSkin();
    poolParty.ChangeSkin();
    dragon.ChangeSkin();
    return 0;
}
           
C++設計模式2——裝飾者模式

3.2 以更換英雄的皮膚為例

#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;

//英雄接口 
class Hero {
public:
    //學習技能
    virtual void LearnSkill() = 0;
};

//具體英雄盲僧
class Mangseng : public Hero
{
protected:
    string name;

public:
    Mangseng(string name)
    {
        this->name = name;
    }

    void LearnSkill()
    {
        cout << name <<"學習了上述技能";
    }
};

//裝飾者基類——技能類
class SKill : public Hero 
{    
protected:
    Hero *m_pHero;//持有一個英雄對象

public:
    SKill(Hero *pHero)
    {
        this->m_pHero = pHero;
    }

    void LearnSkill()
    {
        if (m_pHero != NULL)
            m_pHero->LearnSkill();
    }
};

//盲僧Q技能"天音波/回音擊"
class SKill_Q : public SKill
{
private:
    string m_strSkillName;

public:
    SKill_Q(Hero *pHero, string strSkinName) :SKill(pHero)
    {
        this->m_strSkillName = strSkinName;
    }

    void LearnSkill()
    {        
        cout << "學習了Q技能:" << m_strSkillName << endl;
        m_pHero->LearnSkill();
    }
};

//盲僧W技能"金鐘罩/鐵布衫"
class SKill_W : public SKill
{
private:
    string m_strSkillName;

public:
    SKill_W(Hero *pHero, string strSkinName) :SKill(pHero)
    {
        this->m_strSkillName = strSkinName;
    }

    void LearnSkill()
    {        
        cout << "學習了W技能:" << m_strSkillName << endl;
        m_pHero->LearnSkill();
    }
};

//盲僧E技能"天雷破/摧筋斷骨"
class SKill_E : public SKill
{
private:
    string m_strSkillName;

public:
    SKill_E(Hero *pHero, string strSkinName) :SKill(pHero)
    {
        this->m_strSkillName = strSkinName;
    }

    void LearnSkill()
    {        
        cout << "學習了E技能:" << m_strSkillName << endl;
        m_pHero->LearnSkill();
    }
};

//盲僧R技能"猛龍擺尾"
class SKill_R : public SKill
{
private:
    string m_strSkillName;

public:
    SKill_R(Hero *pHero, string strSkinName) :SKill(pHero)
    {
        this->m_strSkillName = strSkinName;
    }

    void LearnSkill()
    {        
        cout << "學習了R技能:" << m_strSkillName << endl;
        m_pHero->LearnSkill();
    }
};

int main()
{
    Mangseng objMs("盲僧");
    SKill_R r(&objMs, "猛龍擺尾");
    SKill_E e(&r, "天雷破/摧筋斷骨");
    SKill_W w(&e, "金鐘罩/鐵布衫");
    SKill_Q q(&w, "天音波/回音擊");
    q.LearnSkill();
    return 0;
}

           
C++設計模式2——裝飾者模式

繼續閱讀