上次在状态模式中的设计有一个严重的问题,就是如下:
voidCTroll::ChageState(CState* pNewState)
{
deletem_pCurrentState;
m_pCurrentState=pNewState;
Update();
}
在状态切换中不断有内存申请、删除的操作,如果智能体状态切换频繁,会非常消耗时间。要解决这个问题,就要用到Singleton模式。
Singleton模式有多种实现方法,其核心就是把类构造函数私有化,使得外部不能实例化该类。然后在类内部用一个全局的静态函数来完成类的实例化,用一个静态变量保存唯一实例地址。但为了解决线程安全问题,Scott Meyers在《Effective C++》(Item 04)中提出一种更优雅的单例模式实现,使用local static对象(C++中的static对象是指存储区不属于stack和heap、"寿命"从被构造出来直至程序结束为止的对象。其中,函数内的static对象称为local static 对象,而其它static对象称为non-local static对象。对于local static对象,在其所属的函数被调用之前,该对象并不存在,即只有在第一次调用对应函数时,local static对象才被构造出来。)比如以下代码:
classCState_Runaway:publicCState
{
private: //构造函数,拷贝构造和赋值重载全都私有化
CState_Runaway(){};
CState_Runaway(constCState_Runaway&);
CState_Runaway&operator=(constCState_Runaway&);
voidRun(){cout<<"I will run away!"<<endl;}
public:
voidexecute(CTroll* troll);
staticCState_Runaway*GetInstance(); //静态实例化函数
};
静态实例化函数实现如下:
CState_Runaway*CState_Runaway::GetInstance()
{
staticCState_Runaway runaway; //local static对象
return&runaway;
}
静态实例化函数调用:
voidCState_Runaway::execute(CTroll* troll)
{
if(troll->GetSafe())
{
troll->ChageState(CState_Sleep::Getinstance());
/*静态实例化函数第一次调用时local static对象才被执行,实例化成功后,以后再调用就不会执行了。*/
}
else
{
Run();
}
}
最后别忘了把CTroll的析构函数删除状态指针的语句去掉。
CTroll::~CTroll(void)
{
//delete m_pCurrentState; //由于是静态对象,所以不能用delete删除。delete只能删除heap里的对象,而静态对象在全局区里,随程序结束自动销毁。
}
用singleton模式后,每种状态实例只有一个,全局存在,所以以后智能体不管切换多少次状态都不需要再重新申请内存,大大减少运行时间。