昨天简单的设计了一个可供主角方便使用的技能容器,今天进一步研究这个容器如何设计才可以变成公用型容器。
先把昨天的容器代码拿来看一下
class HeroSkillList
{
public:
//获取单例实例方法
static HeroSkillList& Instance(){}
std::shared_ptr<SkillBase> FindSkill(std::string){}
private:
std::map<std::string,std::shared_ptr<SkillBase>> skillList;
HeroSkillList(){}
//省略拷贝构造函数,重载赋值运算符等
}
现在我把它变成一个供敌人使用的容器,看看能否顺利使用
class EnemySkillList
{
public:
//获取单例实例方法
static EnemySkillList& Instance(){}
std::shared_ptr<SkillBase> FindSkill(std::string){}
private:
std::map<std::string,std::shared_ptr<SkillBase>> skillList;
EnemySkillList()
{
//将敌人能使用的技能加入列表
}
//省略拷贝构造函数,重载赋值运算符等
}
直接这样敌人能不能直接使用?大概是可以的,敌人的代码可以向这样
class Enemy:public GameObject
{
public:
void UseSkill()
{
EnemySkillList::Instance().FindSkill(/*技能名*/)->Use();
}
}
完全照搬主角类的模式来做就可以很方便的使用技能。但是这种做法我认为并不是非常好的做法。因为一个游戏中并不止有一种敌人,可能很多的敌人都会使用技能,假设有10种敌人,Enemy1,Enemy2….Enemy10;那么对应的EnemySkillList列表可能就有10种。那么EnemySkillList的很多代码都会被重复编写10遍,这不是我们所希望的。这个List里,至少
static EnemySkillList& Instance(){}
std::shared_ptr<SkillBase> FindSkill(std::string){}
private:
std::map<std::string,std::shared_ptr<SkillBase>> skillList;
这些代码都是被重复编写的,可能还有其他方法也是要被重复写好多遍的,我希望能够有效的重用这些代码,我采取的方法是把这些代码放进一个类中,即SkillListBase,代码如下
template <typename T>
class SkillListBase
{
public:
static T& Instance()
{
static T instance;
return instance;
}
std::shared_ptr<SkillBase> FindSkill(std::string){}
protected:
SkillListBase(){}
~SkillListBase(){}
std::map<std::string,std::shared_ptr<SkillBase>> skillList;
}
这里我直接把技能列表基类做成了单例基类,至于具体为什么单例基类这么设计,网上一搜一大把,这里不多解释。这样可以使代码复用效率大大提升。在一个特定的技能列表中应该这么做,以主角类举例
class HeroSkillList : public SkillListBase<HeroSkillList>
{
private:
friend SkillListBase<HeroSkillList>;
HeroSkillList()
{
//添加技能的代码,可能有100行
}
}
这时这个主角技能列表编写时需要注意三点,第一是继承基类时的写法
class HeroSkillList : public SkillListBase<HeroSkillList>
因为基类时使用泛型的,所以这里需要给出确定的类型,否则编译器会罢工。
第二点是在子类中指定友元
friend SkillListBase<HeroSkillList>;
如果这里不再子类中将基类指定为友元,在基类的Instance方法中,编译器会认为HeroSkillList这个类的构造函数是不可访问的,会拒绝执行代码。
第三点是子类的构造函数,拷贝构造函数,赋值运算符等应声明为私有成员。这样做可以确保外界无法声明一个子类实例,也无法通过继承来创建一个实例。
做出这样的修改后,主角想要使用一个技能应该怎么做?代码大概像这样
class Hero:public GameObject
{
public:
void UseSkill()
{
HeroSkillList::Instance().FindSkill(/*技能名*/)->Use();
}
}
和之前没有变化。那么敌人类呢?
class Enemy:public GameObject
{
public:
void UseSkill()
{
EnemySkillList::Instance().FindSkill(/*技能名*/)->Use();
}
}
敌人类也没有变化。变化的部分在于下面代码
class HeroSkillList : public SkillListBase<HeroSkillList>
{
private:
friend SkillListBase<HeroSkillList>;
HeroSkillList()
{
//添加技能的代码,可能有100行
}
}
class EnemySkillList : public SkillListBase<EnemySkillList>
{
private:
friend SkillListBase<EnemySkillList>;
EnemySkillList()
{
//添加技能的代码,可能有100行
}
}
修改之前的代码长这样
class HeroSkillList
{
public:
//获取单例实例方法
static HeroSkillList& Instance(){}
std::shared_ptr<SkillBase> FindSkill(std::string){}
private:
std::