У меня есть система, которая управляет событиями, которые происходят с несколькими участниками, используя простую систему на основе очередей. 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, который реализует действие, просто возвращая потраченное время, и новое событие «Think» будет добавлено в очередь автоматически.
Проблема, которую я вижу здесь, заключается в том, что реализация классов на основе 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);
}
}
Я мог бы закончить с несколькими десятками таких классов. Если я правильно понимаю, это классическая реализация Шаблон команды . Однако я не чувствую себя хорошо во всех этих классах делегирования и особенно в том, что пишу их все вручную.
Я думал об использовании отражения Java и таких вещей, как Method.invoke () , при передаче экземпляра Method
и предварительно сохраненных аргументов ему в универсальном классе ActorActEvent
, однако это было бы довольно медленный. Я думал написать генератор для всех этих классов, но для меня это выглядит довольно неуклюжим решением.
Если бы это был какой-то современный скриптовый / функциональный язык, я бы в конечном итоге использовал структуру, похожую на блок / закрытие, сначала подготовив ее и вызвав ее, когда придет время. Увы, я не знаю, как сделать это эффективно в Java.
Есть ли какие-нибудь яркие идеи о том, что я могу сделать, чтобы улучшить ситуацию?