【问题标题】:Is there a way to make interface code run at runtime?有没有办法让界面代码在运行时运行?
【发布时间】:2018-05-22 21:29:08
【问题描述】:

我正在努力在我用 Java 创建的简单游戏引擎中实现事件处理。我现在正在努力弄清楚我应该如何注册对象的事件处理程序。我在想,我可以创建一个在创建对象时运行一行代码(public void registerListener(Object listener))的接口。我知道接口无法定义构造函数,因此我正在寻求有关如何处理此问题的指导。现在,我必须在所有具有事件处理程序的对象的构造函数中调用前面提到的代码行,我认为使用接口或类似的东西来减少重复将是一个理想的解决方案。

以下是事件系统的其余代码,以供您查看。谢谢!

EventManager 类:
负责维护将响应事件的方法列表。注册EventHandler时,传入一个类作为参数,它会查找所有带有@EventHandler()注解的方法,并将注解值作为事件类型。

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;

public class EventManager
{
    private HashMap<Class<? extends Event>, ArrayList<Method>> eventCallbackMap;

    public EventManager()
    {
        this.eventCallbackMap = new HashMap<>();
    }

    public void dispatchEvent(Event event)
    {
        ArrayList<Method> callbacks = eventCallbackMap.get(event.getClass());

        if(callbacks == null)
        {
            return;
        }

        for(Method callback : callbacks)
        {
            //TODO: Invoke Method
        }
    }

    public void registerListener(Object listener)
    {
        for(Method method : listener.getClass().getMethods())
        {
            if(method.isAnnotationPresent(EventHandler.class))
            {
                Class<? extends Event> value = method.getAnnotation(EventHandler.class).value();

                if(eventCallbackMap.containsKey(value))
                {
                    eventCallbackMap.get(value).add(method);
                }
                else
                {
                    ArrayList<Method> callbacks = new ArrayList<>();
                    callbacks.add(method);

                    eventCallbackMap.put(value, callbacks);
                }
            }
        }
    }
}

事件类:
非常准系统的抽象类,所有自定义事件都将从中扩展。如果您能告诉我如何改进这门课,我将不胜感激,我将不胜感激。

package events;

public abstract class Event
{
    public Event()
    {
    }
}

EventHandler 类:
将方法定义为事件响应方法的注解。

package events;

import java.lang.annotation.*;

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EventHandler
{
    Class<? extends Event> value();
}

【问题讨论】:

  • 我认为您应该删除注释(为什么使用它?反射不在此处)并制作一个定义EventHandler的常规接口。然后 registerListener 应该采用该类型。

标签: java events event-handling game-engine


【解决方案1】:

是的。您应该使用接口,而不是注释。一个非常快速的示例可能如下所示。这只是一个代码草图,不确定它是否会编译。有改进的余地,但这是基本思想:

interface EventHandler
{
    Set<Event> eventTypes();
    void onEvent(Event event);
}

interface Event
{
    // used as a marker interface, but probably add some methods
}

enum MouseEvent implements Event
{
    ON_CLICK
    //... and whatever else
}

class OnClickEventHandler implements EventHandler
{
    public Set<Event> eventTypes()
    {
        Set<Event> events = new HashSet<>();
        events.add(MouseEvent.ON_CLICK);
        return events;
    }

    public void onEvent(Event event)
    {
        if (event == MouseEvent.ON_CLICK)
        {
            System.out.println("Mouse clicked");
        }
    }
}

class EventManager
{
    private final Map<Event, List<EventHandler>> handlers = new HashMap<>();

    public void registerListener(EventHandler handler)
    {
        for (Event eventType : handler.eventTypes())
        {
            handlers.putIfAbsent(eventType, new ArrayList<>());
            handlers.get(eventType).add(handler);
        }
    }

    public void dispatchEvent(Event event)
    {
        handlers.getOrDefault(event, Collections.emptyList())
            .forEach(handler -> handler.onEvent(event));
    }
}

【讨论】:

  • 谢谢,感谢您的反馈。另外,感谢您向我介绍putIfAbsent()getOrDefault() 函数。
猜你喜欢
  • 1970-01-01
  • 2021-10-13
  • 1970-01-01
  • 2018-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多