Код интерфейса, который работает во время выполнения? - PullRequest
0 голосов
/ 23 мая 2018

Я работаю над обработкой событий для упрощенного игрового движка, над которым я работаю, и у меня большая его часть почти работает.Я сейчас пытаюсь выяснить, как я могу зарегистрировать обработчики событий объектов.Я думал, что смогу создать интерфейс, который запускает строку кода (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);
                }
            }
        }
    }
}

Событиеclass:
Очень простой абстрактный класс, из которого будут расширяться все пользовательские события.Я был бы признателен, если бы вы сообщили мне, как я могу улучшить этот класс, я был бы признателен.

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();
}

1 Ответ

0 голосов
/ 23 мая 2018

Да.Вы должны использовать интерфейс, а не аннотации.Очень быстрый образец может выглядеть следующим образом.Это просто набросок кода, не уверен, что он будет компилироваться.Есть возможности для улучшения, но это основная идея:

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));
    }
}
...