我正在制作一个小游戏模板,世界由节点组成,如下所示:
World
|--Zone
|----Cell
|------Actor
|------Actor
|--------Item
一个World
可以包含多个Zone
对象,一个Zone
可以包含多个Cell
对象,以此类推。
每个对象都实现了Node
接口,该接口有一些方法,如getParent
、getChildren
、update
、reset
等。
我想能够在单个节点上或从节点(由Task
指定)递归地向下执行给定的Task
。
此外,我希望这是一个“可插拔”的系统,即希望玩家/开发人员能够随时添加新类型到树中。我也考虑过从基本类型进行转换:
public void doTask(Actor node)
{
if(!(node instanceof Goblin)) { return; }
Goblin goblin = (Goblin) node;
}
起初,我想使用访问者模式来利用双重分派,允许每个例程(访问者)根据被访问的
Node
类型进行操作。但是,这引起了一些复杂性,特别是当我想向树中添加新的Node
类型时。作为替代,我编写了一个实用类,该类使用反射查找最适用于
Node
的最具体方法。
现在我的担忧是性能; 由于将会有相当多的反射查找和调用,我担心我的游戏的性能(每秒可能有数百或数千次这些调用)会受到影响。这似乎解决了两种模式的问题,但使得每个新
Task
的代码更加丑陋。
在我看来,我有三种选择来允许这种动态分发(除非我漏掉了一些明显/晦涩的东西,这就是为什么我来这里的原因):
访问者模式优点: - 双重分派 - 性能 - 任务中的清晰代码
缺点: - 难以添加新的节点类型(在不修改原始代码的情况下不可能) - 在调用任务时的丑陋代码
使用反射进行动态调用
优点: - 可以随意添加新的节点类型 - 任务非常可定制 - 任务中的清晰代码
缺点: - 性能较差 - 在调用任务时的丑陋代码
强制转换
优点: - 比反射更具性能 - 可能比访问者更加动态 - 调用任务时的清晰代码
缺点: - 代码有异味 - 比访问者性能低(没有双重分派,在每次调用中进行强制转换) - 任务中的丑陋代码
我是否忽略了一些显而易见的东西?我熟悉许多四人帮设计模式,以及游戏编程模式中的模式。在这里任何帮助都将不胜感激。
明确一下,我不是在问哪种方法是“最好”的。我正在寻找这些方法的替代方案。
node.getTasks().forEach(t - > t.doTask(node))
的代码调用。但是在运行时,节点的类型是未知的,这就是为什么要使用反射来选择特定类型的节点所调用的doTask
方法。Task
接口可以接受多种类型,但如果使用该库的开发人员添加了新的节点类型,则它不会成为接口的一部分。 - Caleb Brinkman