我目前正在编写一个游戏,使用基于自编写组件的实体引擎的变体。 当我定义我的实体及其所拥有的组件时,我想使用以下想法正确地对它们进行处理以供系统的其余部分使用:
class Entity {
...
用于识别不同的组件:
enum ComponentID() {
BODY,
GRAPHICS,
INVENTORY;
}
...
应该包含所有组件:
EnumMap<ComponentID, ModelComponent> components = new EnumMap<>(ComponentID.class);
}
首先,我们有一个名为ModelComponent的超类和一些不同的具体子类,如Body,Graphics,AI等,它们扩展了ModelComponent。
组件EnumMap应该保存对实体具有的所有ModelComponents的引用。 当我想向系统询问特定组件时,就会出现问题。如果我想获取body组件,例如因为物理类想要计算一些碰撞,我会编写如下代码:
public Body getBody() {
return (Body) components.get(ComponentID.BODY);
}
需要演员,因为我的游戏中的某个地方,如果我想访问实体的速度,我会调用:
Vector2 velocity = entity.getBody().getVelocity();
但是,getVelocity()是一个仅在具体子类Body中定义的方法。
我的问题是:这是对子类的向下转换的正确用法吗?我不知道,是否可以通过更好的设计来避免向下转换,因为显然一个Graphics组件将完成与Body组件完全不同的东西,所以它们都将具有完全不同的方法。
修改
我忘了提及以下可能对回答这个问题很重要的细节:
1)当然,还有更多具体的实体子类,如Player,Enemy,Trigger等,它们都应该具有不同的ModelComponents组合。 玩家不需要像敌人那样的AI组件。
2)我对这个重构的目标是摆脱字段
Body body;
Graphics graphics;
Inventory inventory;
Ai ai;
因为在我的游戏中实例化的每个实体都会拥有所有这些字段。 enummap可以消除这个问题,因为我将使用以下代码行替换所有getXXX()方法:
public ModelComponent get(ComponentID id) {
return components.get(id);
}
答案 0 :(得分:1)
简短的回答是:不。因为您正在添加隐含逻辑。在这种情况下,向下转换是有效的,因为你知道它是正确的,因为在代码中你将设置正确的对象。但编译器无法检查这一点,也可能无法检查其他开发人员。所以其他人可以更改代码,编译器不会抱怨,只有在运行时才会抛出类转换异常。