我正在为 RTS 游戏构建 AI。(对于Spring RTS 引擎,如果有人感兴趣的话。)我设置它的方式主要由一组组件组成,这些组件通过触发的事件进行通信。每个组件都有一个方法 handleEvent(Event) 来接收其他组件触发的事件。
事件是一个接口。存在一个层次结构,每个子类都提供有关它们所代表的事件的更详细信息,可以使用特定于该类的 getter 方法来访问这些信息。例如,UnitGainedEvent 类实现了 Event 接口。这个类有一个子类 UnitFinishedEvent(对于任何好奇的人来说,它表示一个单元或建筑物的建造已经完成。)
不是每个组件都会对所有事件感兴趣,所以我想让组件简单地选择他们感兴趣的事件并只接收这些事件。此外,可能的事件集是可扩展的,因此让组件为每种事件类型指定方法不是一个有效的选项。最初我认为访问者模式可能会帮助我解决这个问题,但它失败了,因为它还需要一组固定的事件类型。(我不是 100% 确定我正确理解了模式。如果我错了,请纠正我。)
到目前为止,我发现的唯一解决方案是实现每个组件的 handleEvent(Event) 方法,如下所示:
public int handleEvent(Event event)
{
if (event instanceof UnitGainedEvent)
{
UnitGainedEvent unitGainedEvent = (UnitGainedEvent) event;
// things to do if I lost a unit
}
else if (event instanceof UnitLostEvent)
{
UnitLostEvent unitLostEvent = (UnitLostEvent) event;
// things to do if I lost a unit
}
// etc.
}
但是,我真的不喜欢将事件强制转换为特定的 Event 类。现在,记住方法重载可用于根据参数的运行时类型调用不同的方法,我很快想出了一个绝妙的解决方案,既简单又优雅:我可以创建一个带有空实现的基类 handleEvent(事件),并且简单地让子类通过创建方法handleEvent(UnitGainedEvent unitGainedEvent)来接收他们感兴趣的事件,例如。为了确保它可以工作,我设置了一个快速测试用例:
public class Main
{
public static void main(String[] args)
{
handleEvent(new UnitGainedEvent(null));
}
public static void handleEvent(Event event)
{
System.out.println("Handling generic Event");
}
public static void handleEvent(UnitGainedEvent event)
{
System.out.println("Handling UnitGainedEvent");
}
}
令我非常满意的是,这段代码实际上打印了“Handling UnitGainedEvent”。于是我着手实施。
我的 Component 基类看起来像这样:(嗯,不是真的。这是 Component 类剥离了与我想演示的问题无关的所有内容。)
public class Component
{
public void handleEvent(Event event)
{
System.out.println("Handling Event");
}
}
这是一个子类的例子:
public class SomeComponent extends Component
{
public void handleEvent(UnitGainedEvent unitGainedEvent)
{
System.out.println("Handling UnitGainedEvent");
}
}
为了测试设置,我使用以下主类:
public class Main
{
public static void main(String[] args)
{
Component component = new SomeComponent();
component.handleEvent(new UnitGainedEvent(null));
}
}
所以我运行了代码,令我惊讶的是,结果是一个打印整齐的“处理事件”。有趣的是,如果我将组件变量的类型更改为 SomeComponent,它会打印出“Handling UnitGainedEvent”。由于某种原因,系统会盲目地调用 Component 类的 handleEvent(Event) 方法,而不是重载 SomeComponent 的 handleEvent(UnitGainedEvent)。(我很想听听 Sun 在这背后的推理,认为这与我的问题并不真正相关 - 不像他们会仅仅因为少数人会发现它是一个非常有用的功能而修复它。)
淘网告诉我其他人也遇到了同样的问题。从我找到的微不足道的信息来看,很少有人,但仍然有人,尽管我发现有关一般方法重载和覆盖的信息比我想知道的要多。但是,最后,我找不到解决方案。
现在,我的(相当明显的)问题是,有没有办法解决这个问题?如果做不到这一点,谁能想到或帮我找到另一个同样方便的解决方案?
编辑:我简直不敢相信我在十分钟后就有了答案。我很惊喜。:) 但是,到目前为止,大多数答案都以一种或另一种形式表明我为每种可能的事件类型制作了一种单独的方法。从技术上讲这是可能的,但这需要我回到代码中并在每次有人提出新的事件类型时添加一个新方法。我学到的是糟糕的编码实践。(另外,我已经有大约 20 多种事件类型,但我什至还没有完成。)相反,我宁愿使用涉及强制转换的解决方案,如上所述。至少这样我可以确保未知的事件类型被简单地忽略,让我可以自由地只处理那些我想使用它们的事件。然而,我真的希望有一个结合了两者优点的解决方案。没有铸造,
非常感谢,Loid Thanead