游戏编程模式之父类沙盒模式
使用基类提供的操作集合来定义子类中的行为。
(摘自《游戏编程模式》)
沙盒(英语:sandbox,又译为沙箱)是一种安全机制,为运行中的程序提供的隔离环境。
(摘自维基百科)
在我看来,子类沙盒模式就是一种是代码更紧凑为目的的模式,它更好的约束了程序员对继承的肆意使用。为什么这么说呢?首先我们要了解什么是子类沙盒。上面的引用也提到了沙盒的定义,那么,子类沙盒实质上就是将子类需要用到的相同操作(函数)全部整合到父类中实现。对各个模块函数、遍历、实例的引用全部让父类去做,这样就能避免这一类跨模块调用的代码散落在子类中。
子类沙盒也可以被称为父类实现了子类需要调用的API。
沙盒模式适用于以下情况:
- 父类的子类数量众多。
- 子类拥有许多共有的操作。
- 子类有重叠代码
- 你希望这些继承类与程序其他代码的耦合最小化。
示例
//父类
class Parent
{
public:
virtual ~Parent(){}
protected:
virtual void activate()=0;
/*子类沙盒*/
double GetCharaPosX()
{
if(charaSys!=nullptr)
return charaSys.main.position.x;
return Double.default;
}
double GetCharaPosY()
{
if(charaSys!=nullptr)
return charaSys.main.position.y;
return Double.default;
}
double GetCharaPosZ()
{
if(charaSys!=nullptr)
return charaSys.main.position.z;
return Double.default;
}
void PlaySound(SoundId sound)
{
if(audioSys!=nullptr)
audioSys.Play(sound);
}
void SpawnParticle(ParticleType type,int count)
{
if(particleSys!=nullptr)
particleSys.Spawn(type,count);
}
void CharacterMove(Vector3 direction,double speed)
{
if(charaSys!=nullptr)
charaSys.main.Move(direction,speed);
}
private:
AudioSystem audioSys;
ParticleSystem particleSys;
CharacterSystem charaSys;
}
//子类
class Child : Parent
{
public:
virtual void activate()
{
//调用沙盒函数等...
if(GetCharaPosY()<0)
PlaySound(SoundId.Drop);
}
}
其他想说
如何抉择
其实沙盒模式复杂度不在实现,而在思想和抉择。在这一模式下,编写者需要抉择什么内容应该放在父类沙盒中,什么内容应该由子类自己调用——我们不可能让父类完成所有继承子类需要的功能,因为这样的父类会变得太过庞大而难以维护。
若如果仅仅是对外部系统调用的二次封装,那么放在父类的沙盒中就不会带来多少价值。这样做的唯一有点仅仅是将子类与外部系统的联系转化为子类和父类的联系罢了,甚至比直接调用还增加了一层调用。
可尝试仅提供外部系统的实例
父类沙盒中的功能越详细,父类的规模也就越庞大。尝试做如下处理可以极大的减小父类沙盒的规模。
class AudioSystem
{
void Play(SoundId sound);
}
class Parent
{
protected:
//父类沙盒
AudioSystem& GetAudioSys()
{
return audioSys;
}
private:
AudioSystem audioSys;
}