# 子类沙盒

“使用基类提供的操作集合来定义子类中的行为”

一个基类定义了一个抽象的沙盒方法和一些预定义的操作集合。通过将它们设置为受保护的状态以确保它们仅
供子类使用。每个派生出的沙盒子类根据父类提供的操作来实现沙盒函数。

Superpower基类

```cpp
class Superpower 
{
public:　 
　virtual ~Superpower() {} 

protected:
　virtual void activate() = 0;　　

　void move(double x, double y, double z)　 
　{　　 
　// Code here...　 

　}　

　void playSound(SoundId sound)　 
　{　　 
　　// Code here...　

　}　　

　void spawnParticles(ParticleType type, int count) 
　{　　 
　　// Code here...　 

 } 
};
```

activate() 就是沙盒函数，由于它是抽象虚函数，因此子类必须要重写它。

其他的受保护函数 move、playSound、spawnParticles 都是所提供的操作，
这就是子类在 activate 函数实现时能够调用的函数。

创造一些放射性蜘蛛并创建一个power类

```cpp
class SkyLaunch : public Superpower 
{ 
protected:　 
　virtual void activate()　 
　{　　 
　　 move(0, 0, 20);　　　 // Spring into the air.

　　
　　 playSound(SOUND_SPROING);　　 
　　 spawnParticles(PARTICLE_DUST, 10);　　 
　} 
}; 
```

继续优化,将获取英雄位置方法提到Superpower基类

```cpp
class Superpower
{
protected:
　double getHeroX() { /* Code here... 

*/ }
　double getHeroY() { /* Code here...

 */ }
　double getHeroZ() { /* Code here...

 */ }

　// Existing stuff...

};
```

在SkyLaunch子类中使用它们

```cpp
class SkyLaunch : public Superpower 
{ 
protected:　 
　virtual void activate()　
　{　　 
　　if (getHeroZ() == 0)　　
　　{　　　
　　　　// On the ground, so spring into the air.

　 
　　　　playSound(SOUND_SPROING);
　　　　spawnParticles(PARTICLE_DUST, 10);　　
　　　　move(0, 0, 20);　　 
　　}　　 
　　else if (getHeroZ() < 10.0f)　 
　　{　　　 
　　　　// Near the ground, so do a double jump.

　 
　　　　playSound(SOUND_SWOOP);　　　
　　　　move(0, 0, getHeroZ() - 20);　　
　　}　　
　　else　　
　　{　　　
　　　　 // Way up in the air, so do a dive attack.　　

　
　　　　 playSound(SOUND_DIVE);　　　
　　　　 spawnParticles(PARTICLE_SPARKLES, 1);　　
　　　　 move(0, 0, -getHeroZ());　 
　　}　
　} 
}; 
```

像Superpower基类中playSound可能有，不想让子类接触的状态，比如

```cpp
void Superpower::playSound(SoundId sound)
{
    soundEngine_.play(sound);
}
```

直接提供函数，还是由包含它们的对象提供

例如可能，基类塞的方法越来越臃肿

```cpp
class Superpower
{
protected:
　 void playSound(SoundId sound) { /* Code...
*/ }
　 void stopSound(SoundId sound) { /* Code... 

*/ }
　 void setVolume(SoundId sound) { /* Code...

 */ }

　 // Sandbox method and other operations...

};
```

可以将基类内容封装出来，用组合的方式

```cpp
class SoundPlayer
{
　void playSound(SoundId sound) { /* Code... 

*/ }
　void stopSound(SoundId sound) { /* Code... 

*/ }
　void setVolume(SoundId sound) { /* Code...

 */ }
};
```

在Superpower中使用SoundPlayer

```cpp
class Superpower 
{ 
protected:　 
　SoundPlayer& getSoundPlayer()　 
　{　　 
　　 return soundPlayer_;　 
　}　　

　// Sandbox method and other operations... 

private:
　SoundPlayer soundPlayer_; 
}; 
```

子类中通过getSoundPlayer方法返回的SoundPlayer对象执行相应方法。

具体怎么做这需要具体应用情况下自己思考。

## 基类如何获取其所需的状态

### 把它传递给基类构造函数

```cpp
class Superpower 
{ 
public:　 
　Superpower(ParticleSystem* particles)　 
　: particles_(particles)　{}　　
　// Sandbox method and other operations...　


private:　 
　ParticleSystem* particles_;　　 
};

class SkyLaunch : public Superpower 
{ 
public:　 
　SkyLaunch(ParticleSystem* particles)　 
　: Superpower(particles)　 {} 
};
```

这样不得不在每个子类构造函数都做处理。

### 进行分段初始化

```cpp
Superpower* power = new SkyLaunch(); 
power->init(particles);

Superpower* createSkyLaunch(
　　ParticleSystem* particles)
{　 
　Superpower* power = new SkyLaunch();　 
　power->init(particles);　 
　return power; 
}
```

### 状态静态化

如果所有实例都共用同一个，则可以考虑，将状态静态化,尽早地把init调用给初始化号。

```cpp
class Superpower 
{ 
public:　 
　static void init(ParticleSystem* particles)　 
　{　　 
　　 particles_ = particles;　 
　}　　

　// Sandbox method and other operations... 

 
private:　 
　static ParticleSystem* particles_; 
};
```

### 使用服务定位器

从某处，用的时候去获取

```cpp
class Superpower 
{ 
protected:　 
　void spawnParticles(ParticleType type, int count)　　
　{　　 
　　ParticleSystem& particles = Locator::getParticles();　　　
　　particles.spawn(type, count);　 
　}　　

　// Sandbox method and other operations... 

}; 
```

这种方式大多数情况是体验比较好的。
