我有一个系统,可以使用简单的基于队列的系统管理发生在多个actor上的事件。 Event
是一个简单的类,它有时间和抽象方法fire()
。 Actor
是一个实现两种方法的简单接口 - think()
和act()
。每个演员都有2个基本事件,实现方式如下:
public class ActorThinkEvent extends Event {
private Actor actor;
public ActorThinkEvent(Actor actor, long time) {
super(time);
this.actor = actor;
}
public void fire() {
Main.game.queue.add(actor.think());
}
}
public abstract class ActorActEvent extends Event {
protected Actor actor;
protected ActorActEvent(Actor actor, long time) {
super(time);
this.actor = actor;
}
public void fire() {
long spent = act();
Main.game.queue.add(new ActorThinkEvent(actor, time + spent));
}
public abstract long act();
}
这样,“思考”调用是固定的,它应该生成一个ActorActEvent
,它将被添加到全局队列中,而“代理”调用是使用一个自定义的基于ActorActEvent的类完成的,它实现了动作,只返回花费的时间,新的“思考”事件将自动添加到队列中。
我在这里看到的问题是基于ActorActEvent的类的实现归结为从ActorActEvent.act()
到具有预存参数的Actor
类的某种方法的简单委托,即我的所有ActEvent类看起来都非常类似:
public class ActorMoveEvent extends ActorActEvent {
private Coords delta;
public ActorMoveEvent(Actor actor, long time, Coords delta) {
super(actor, time);
this.delta = delta;
}
public long act() {
return actor.moveBy(delta);
}
}
public class ActorReloadEvent extends ActorActEvent {
public ActorReloadEvent(Actor actor, long time) {
super(actor, time);
}
public long act() {
return actor.reload();
}
}
public class ActorPickupEvent extends ActorActEvent {
private ItemStash wantedItems;
public ActorPickupEvent(Actor actor, long time, ItemStash wantedItems) {
super(actor, time);
this.wantedItems = wantedItems;
}
public long act() {
return actor.pickupItems(wantedItems);
}
}
我可能会结束几十个这样的课程。如果我理解正确,那就是Command pattern的经典实现。但是,我对所有这些授权类都感觉不舒服,特别是关于手动编写它们。
我想过使用Java的反射和像Method.invoke()这样的东西,同时在通用Method
类中传递ActorActEvent
实例和预先存储的参数,但是,它会相当慢。我想为所有这些类编写一个生成器,但对我来说它看起来是一个相当笨拙的解决方案。
如果它是一些现代脚本/函数语言,我最终会使用类似块/闭包的结构,首先准备它并在时机到来时调用它。唉,我不知道如何在Java中有效地实现它。
对于如何改善这种情况,我们有什么好主意吗?
答案 0 :(得分:1)
我的建议是沿着反思路走下去。在这种情况下,担心“它会相当慢”是不成熟的。在过去的十年里,反射的表现相当不错,你将能够缓存你的Method
对象,以节省重新分析名称所花费的时间(这可能是最大的性能影响)。这种方法灵活且快速实施。
如果你真的喜欢你的闭包,你可以为你的活动试验匿名的内部类。有一些限制 - 您仍然需要声明您的方法,因此它更加冗长,并且您需要将变量声明为final,以便从内部类中访问它们。这种方法将为您提供静态类型的所有性能和安全性,但您仍然需要为每个事件创建一个类。
从历史上看,事件表现出“两个世界中最糟糕的”行为并且在Object
附近传递,依靠目标知道如何施放和处理它们。