天天看点

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——装饰者模式

继续阅读