我正在为我正在开发的一个小游戏创建一个面向组件的系统。基本结构如下: 游戏中的每个对象都由一个“GameEntity”组成;一个容器,其中包含指向“组件”类中项目的指针向量。
组件和实体通过调用组件的父 GameEntity 类中的 send 方法相互通信。send 方法是一个模板,它有两个参数,一个 Command(它是一个枚举,包括 STEP_TIME 等指令)和一个泛型类型“T”的数据参数。send 函数循环遍历 Component* 向量并调用每个组件的接收消息,由于模板使用方便地调用对应数据类型 T 的重载接收方法。
然而,问题出现的地方(或者更确切地说是不便)是 Component 类是一个纯虚函数,并且总是会被扩展。由于不允许对模板函数进行虚拟化的实际限制,我必须在头文件中为每个可能被组件使用的数据类型声明一个虚拟接收函数。这不是很灵活也不是可扩展的,而且至少在我看来,这似乎违反了不要不必要地复制代码的 OO 编程精神。
所以我的问题是,如何修改下面提供的代码存根,以使我的面向组件的对象结构尽可能灵活,而不使用违反最佳编码实践的方法
以下是每个类的相关标头存根,以及可能以何种方式使用扩展组件类的示例,以便为我的问题提供一些上下文:
游戏实体类:
class Component;
class GameEntity
{
public:
GameEntity(string entityName, int entityID, int layer);
~GameEntity(void){};
//Adds a pointer to a component to the components vector.
void addComponent (Component* component);
void removeComponent(Component*);
//A template to allow values of any type to be passed to components
template<typename T>
void send(Component::Command command,T value){
//Iterates through the vector, calling the receive method for each component
for(std::vector<Component*>::iterator it =components.begin(); it!=components.end();it++){
(*it)->receive(command,value);
}
}
private:
vector <Component*> components;
};
组件类:#include "GameEntity.h" 类组件
{
public:
static enum Command{STEP_TIME, TOGGLE_ANTI_ALIAS, REPLACE_SPRITE};
Component(GameEntity* parent)
{this->compParent=parent;};
virtual ~Component (void){};
GameEntity* parent(){
return compParent;
}
void setParent(GameEntity* parent){
this->compParent=parent;
}
virtual void receive(Command command,int value)=0;
virtual void receive(Command command,string value)=0;
virtual void receive(Command command,double value)=0;
virtual void receive(Command command,Sprite value)=0;
//ETC. For each and every data type
private:
GameEntity* compParent;
};
Component 类的可能扩展:
#include "Sprite.h"
#include "Component.h"
class GraphicsComponent: Component{
public:
GraphicsComponent(Sprite sprite, string name, GameEntity* parent);
virtual void receive(Command command, Sprite value){
switch(command){
case REPLACE_SPRITE: this->sprite=value; break
}
}
private:
Spite sprite;
}
我应该使用空指针并将其转换为适当的类型吗?这可能是可行的,因为在大多数情况下,类型将从命令中得知,但同样不是很灵活。