《C++新经典设计模式》之第4章 策略模式

策略模式.cpp
#include <iostream>
#include <memory>
using namespace std;

// if或switch分支不稳定,经常改动时,考虑引入算法独立到策略类中去实现

// 依赖倒置原则
// 高层组件不应该依赖于底层组件(具体实现类),两者都应该依赖于抽象层
// 面向接口(抽象层)编程,而不是针对实现(实现类)编程

namespace ns0
{
    enum ItemAddlife // 增加补充生命值道具
    {
        LF_BXD, // 补血丹
        LF_DHD, // 大还丹
        LF_SHD, // 守护丹
    };

    class Fighter
    {
    protected:
        int m_life; // 人物生命值
        int m_magic;
        int m_attack;

    public:
        Fighter(int life, int magic, int attack) : m_life(life), m_magic(magic), m_attack(attack) {}
        virtual ~Fighter() {}

    public:
        void UseItem(ItemAddlife djtype) // 吃药补充生命值
        {
            switch (djtype) // 道具类型
            {
            case LF_BXD:       // 补血丹
                m_life += 200; // 补充200点生命值
                // if (主角中毒了)
                //{
                //     停止中毒状态,也就是主角吃药后就不再中毒
                // }
                // if (主角处于狂暴状态)
                {
                    m_life += 400;  // 额外再补充400点生命值
                    m_magic += 200; // 魔法值也再补充200点
                }
                break;
            case LF_DHD:       // 大还丹
                m_life += 300; // 补充300点生命值
                break;
            case LF_SHD:       // 守护丹
                m_life += 500; // 补充500点生命
                break;
            }
        }
    };

    class F_Warrior : public Fighter // “战士”类
    {
    public:
        F_Warrior(int life, int magic, int attack) : Fighter(life, magic, attack) {}
    };

    class F_Mage : public Fighter // “法师”类
    {
    public:
        F_Mage(int life, int magic, int attack) : Fighter(life, magic, attack) {}
    };
}

namespace ns1
{
    class Fighter;
    class ItemStrategy // 道具策略类的父类
    {
    public:
        virtual ~ItemStrategy() {}
        virtual void UseItem(Fighter *const mainobj) = 0;
    };

    // 战斗者父类
    class Fighter
    {
        shared_ptr<ItemStrategy> itemstrategy;

    protected:
        int m_life; // 人物生命值
        int m_magic;
        int m_attack;

    public:
        Fighter(int life, int magic, int attack) : m_life(life), m_magic(magic), m_attack(attack) {}
        virtual ~Fighter() {}

    public:
        void SetItemStrategy(const shared_ptr<ItemStrategy> &strategy) { itemstrategy = strategy; } // 设置道具使用的策略
        void UseItem() { itemstrategy->UseItem(this); }                                             // 使用道具(吃药)
        int GetLife() const { return m_life; }
        void SetLife(int life) { m_life = life; }
    };

    class F_Warrior : public Fighter // “战士”类
    {
    public:
        F_Warrior(int life, int magic, int attack) : Fighter(life, magic, attack) {}
    };

    class F_Mage : public Fighter // “法师”类
    {
    public:
        F_Mage(int life, int magic, int attack) : Fighter(life, magic, attack) {}
    };

    class ItemStrategy_BXD : public ItemStrategy // 补血丹策略类
    {
    public:
        void UseItem(Fighter *const mainobj) override { mainobj->SetLife(mainobj->GetLife() + 200); }
    };

    class ItemStrategy_DHD : public ItemStrategy // 大还丹策略类
    {
    public:
        void UseItem(Fighter *const mainobj) override { mainobj->SetLife(mainobj->GetLife() + 300); }
    };

    class ItemStrategy_SHD : public ItemStrategy // 守护丹策略类
    {
    public:
        void UseItem(Fighter *const mainobj) override { mainobj->SetLife(mainobj->GetLife() + 500); }
    };
}

namespace ns2
{
    class M_Undead // 亡灵类怪物
    {
    public:
        void getinfo() const { cout << "M_Undead" << endl; }
    };
    class M_Element // 元素类怪物
    {
    public:
        void getinfo() const { cout << "M_Element" << endl; }
    };
    class M_Mechanic // 机械类怪物
    {
    public:
        void getinfo() const { cout << "M_Mechanic" << endl; }
    };

    class F_Warrior // 战士主角
    {
    public:
        void attack_enemy_undead(const shared_ptr<M_Undead> &pobj) // 攻击亡灵类怪物
        {
            pobj->getinfo(); // 可以调用亡灵类怪物相关的成员函数
        }

    public:
        void attack_enemy_element(const shared_ptr<M_Element> &pobj) // 攻击元素类怪物
        {
            pobj->getinfo(); // 可以调用元素类怪物相关的成员函数
        }
    };
}

namespace ns3
{
    class Monster // 作为所有怪物类(抽象层)
    {
    public:
        virtual ~Monster() {}
        virtual void getinfo() const = 0; // 纯虚函数
    };

    class M_Undead : public Monster // 亡灵类怪物
    {
    public:
        void getinfo() const override { cout << "M_Undead" << endl; }
    };
    class M_Element : public Monster // 元素类怪物
    {
    public:
        void getinfo() const override { cout << "M_Element" << endl; }
    };
    class M_Mechanic : public Monster // 机械类怪物
    {
    public:
        void getinfo() const override { cout << "M_Mechanic" << endl; }
    };

    class F_Warrior // 战士主角
    {
    public:
        void attack_enemy(const shared_ptr<Monster> &pobj) // 击杀怪物
        {
            pobj->getinfo(); // 可以调用怪物相关的成员函数
        }
    };
}

int main()
{
#if 0
    using namespace ns0;
    shared_ptr<Fighter> prole_war(new F_Warrior(1000, 0, 200)); // 这没有采用工厂模式,如果主角很多,可以考虑采用工厂模式创建对象
    prole_war->UseItem(LF_DHD);
#endif

#if 0
    using namespace ns1;
    // 创建主角
    shared_ptr<Fighter> prole_war(new F_Warrior(1000, 0, 200));

    // 吃一颗大还丹
    prole_war->SetItemStrategy(make_shared<ItemStrategy_DHD>()); // 主角设置大还丹策略,准备吃大还丹
    prole_war->UseItem();                                        // 主角吃大还丹

    // 再吃一颗补血丹
    shared_ptr<ItemStrategy> strateby2(new ItemStrategy_BXD()); // 创建补血丹策略
    prole_war->SetItemStrategy(strateby2);                      // 主角设置补血丹策略,准备吃补血丹
    prole_war->UseItem();                                       // 主角吃补血丹
#endif

#if 0
    using namespace ns2;
    shared_ptr<F_Warrior> pobjwar(new F_Warrior());

    pobjwar->attack_enemy_undead(make_shared<M_Undead>()); // 攻击一只亡灵类怪物

    shared_ptr<M_Element> pobjelm(new M_Element());
    pobjwar->attack_enemy_element(pobjelm); // 攻击一只元素类怪物
#endif

#if 1
    using namespace ns3;
    shared_ptr<F_Warrior> pobjwar(new F_Warrior());

    pobjwar->attack_enemy(make_shared<M_Undead>()); // 攻击一只亡灵类怪物

    shared_ptr<Monster> pobjelm(new M_Element());
    pobjwar->attack_enemy(pobjelm); // 攻击一只元素类怪物
#endif

    return 0;
}
12-16 19:44