Java设计模式:事件系统,给定actor的多个动作

时间:2011-01-09 22:38:35

标签: java events design-patterns command queue

我有一个系统,可以使用简单的基于队列的系统管理发生在多个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中有效地实现它。

对于如何改善这种情况,我们有什么好主意吗?

1 个答案:

答案 0 :(得分:1)

我的建议是沿着反思路走下去。在这种情况下,担心“它会相当慢”是不成熟的。在过去的十年里,反射的表现相当不错,你将能够缓存你的Method对象,以节省重新分析名称所花费的时间(这可能是最大的性能影响)。这种方法灵活且快速实施。

如果你真的喜欢你的闭包,你可以为你的活动试验匿名的内部类。有一些限制 - 您仍然需要声明您的方法,因此它更加冗长,并且您需要将变量声明为final,以便从内部类中访问它们。这种方法将为您提供静态类型的所有性能和安全性,但您仍然需要为每个事件创建一个类。

从历史上看,事件表现出“两个世界中最糟糕的”行为并且在Object附近传递,依靠目标知道如何施放和处理它们。