假设你还是游戏程序员。游戏策划想让你实现补血的道具,主要有三种:补血丹,能够补充200生命;大还丹,补充300生命;守护丹,补充500生命。
我们在 模板方法模式 中已经实现了两种主角:战士和法师。可以在他们之中增加一个函数,用来给自己恢复生命值。
namespace hjl_project1
{
//增加补充生命值的道具
enum ItemAddLife
{
LF_BXD, //补血丹
LF_DHD, //大还丹
LF_SHD, //守护丹
};
//抽象类
class Fighter
{
public:
Fighter(int life, int magic, int attack)
: m_life(life), m_magic(magic), m_attack(attack) {}
virtual ~Fighter() {}
//使用药品的函数
void UseItem(ItemAddLife djtype)
{
if (djtype == LF_BXD)
{
cout << "使用了补血丹,增加200生命" << endl;
m_life += 200;
}
else if (djtype == LF_DHD)
{
cout << "使用了大还丹,增加300生命" << endl;
m_life += 300;
}
else if (djtype == LF_SHD)
{
cout << "使用了守护丹,增加500生命" << endl;
m_life += 500;
}
}
protected:
//角色属性
int m_life; //生命
int m_magic; //魔法值
int m_attack; //攻击力
};
//战士类
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) {}
};
}
上面的代码从程序的功能上来看没什么问题,但从面向对象的视角来看,就会有一些问题。
下面我们使用策略模式对上面这段代码进行改造。
我们给各种补血药品设置一个道具类抽象父类,这些药品增加多少血量,则是由各自的类实现。而主角类则只需要设置一个道具类的指针,即可使用药品。
//Fighter.hpp
namespace hjl_project2
{
class ItemStrategy;
//抽象类
class Fighter
{
public:
Fighter(int life, int magic, int attack)
: m_life(life), m_magic(magic), m_attack(attack) {}
virtual ~Fighter() {}
//设置策略类的指针
void SetItemStrategy(ItemStrategy *strategy);
//使用道具
void UseItem();
//获取生命值
int GetLife();
//设置生命值
void SetLife(int life);
protected:
//角色属性
int m_life; //生命
int m_magic; //魔法值
int m_attack; //攻击力
//指向道具策略类的指针
ItemStrategy *itemstrategy = nullptr;
};
//战士类
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) {}
};
}
//在.cpp文件实现.hpp的成员函数
//Fighter.cpp
#include "Fighter.hpp"
#include "ItemStrategy.hpp"
void hjl_project2::Fighter::SetItemStrategy(ItemStrategy *strategy)
{
itemstrategy = strategy;
}
//使用道具
void hjl_project2::Fighter::UseItem()
{
itemstrategy->UseItem(this);
}
//获取生命值
int hjl_project2::Fighter::GetLife()
{
return m_life;
}
//设置生命值
void hjl_project2::Fighter::SetLife(int life)
{
m_life = life;
}
//ItemStrategy.hpp
#include "Fighter.hpp"
namespace hjl_project2
{
//道具策略类的父类
class ItemStrategy
{
public:
virtual void UseItem(Fighter *mainobj) = 0;
~ItemStrategy(){};
};
//补血丹的策略类
class ItemStrategy_BXD : public ItemStrategy
{
public:
void UseItem(Fighter *mainobj)
{
cout << "使用了补血丹,增加200生命值" << endl;
mainobj->SetLife(mainobj->GetLife() + 200);
}
};
//大还丹的策略类
class ItemStrategy_DHD : public ItemStrategy
{
public:
void UseItem(Fighter *mainobj)
{
cout << "使用了大还丹,增加300生命值" << endl;
mainobj->SetLife(mainobj->GetLife() + 300);
}
};
//守护丹的策略类
class ItemStrategy_SHD : public ItemStrategy
{
public:
void UseItem(Fighter *mainobj)
{
cout << "使用了守护丹,增加500生命值" << endl;
mainobj->SetLife(mainobj->GetLife() + 500);
}
};
}
定义一系列算法(策略类),将每个算法封装起来,让它们可以互相替换。
也就是说,策略模式通常把一系列算法封装到一系列具体策略类中来作为抽象策略类的子类,然后根据需要来使用这些子类。
这和“依赖倒置原则”非常像。
策略模式中有三种角色:
策略模式的优点:
策略模式的缺点: