Как привести объект к заданному универсальному типу, чтобы я мог передать этот объект методу - PullRequest
1 голос
/ 20 марта 2019

У меня есть класс "Event" с одним общим аргументом - T. Это тип Event и всегда интерфейс.Слушатель событий должен реализовывать типы событий, которые он хочет «прослушать».

Например:

public class GuiHandler implements Startup, GuiChanged

Но есть только один способ зарегистрировать этот слушатель событий.Просто возьмите все события, которые он реализует, и вызовите метод «register» с экземпляром прослушивателя событий или ссылкой на метод.

Я пытаюсь создать класс «EventManager», который мог бы определять, реализует ли класс данного объекта «event.getType».() (который возвращает T события) "и, если это так, приведите объект к этому типу события и зарегистрируйтесь в событии.

public static void register(Object listener) {
    for (Event<?> event : Event.EVENTS)
        if (listener.getClass().isInstance(event.getType()))
            event.register(event.getType().cast(listener));
}

Но по какой-то причине он говорит

Регистр метода (захват # 3-из?) В типе Event не применим для аргументов (захват # 4-из?)

События создаются следующим образом:

new Event<>(GuiChanged.class, (listeners) -> 
    (/*some event specific arguments*/) -> {
        for (GuiChanged event : listeners) {
            event.onGuiSchnged(/*some event specific arguments*/);
        }
    });

И конструктор:

public Event(Class<T> type, Function<T[], T> functionToUse) {
        this.type = type;
        this.functionToUse = functionToUse;
        EVENTS = Arrays.copyOf(EVENTS, EVENTS.length + 1);
        EVENTS[EVENTS.length - 1] = this;
    }

Пожалуйста, помогите.Я верю, что это возможно.

Ответы [ 2 ]

0 голосов
/ 21 марта 2019

Хорошо, решение простое.Все, что мне нужно было сделать, это удалить <?> из массива «EVENTS» и просто использовать «isAssignableFrom», чтобы проверить, реализует ли слушатель данный тип события.Это работает сейчас.

0 голосов
/ 20 марта 2019

На мой взгляд, вы должны использовать другой дизайн.В настоящее время ваш Event класс отвечает за удержание всех своих слушателей, но теоретически событие должно содержать только связанные данные события.

public class Event<T> {
    private Class<T> eventClass;
    private T data;

    // rest ommitted for brevity
}

EventListener содержит связанный тип событий, которые он должен обработать, и сам метод обработки.

public interface EventListener<T> {
    Class<T> getType();
    void notify(T event);
}

Ваш EventManager затем отвечает за удержание слушателей ипожарные события.Я использовал Map здесь, чтобы быстро идентифицировать слушателей, которые должны получать уведомления о конкретном событии.

public class EventManager {

    private Map<Class<?>, EventListener<?>> listeners = new HashMap<>();

    public registerListener(EventListener<?> listener) {
        // ...
    }

    public void fire(Event<?> event) {
        EventListener<?> listener = listeners.get(event.getEventClass());
        if(listener != null) {
            listener.notify(event);
        }
    }
} 

Конечно, вы можете удерживать только один EventListener на тип в приведенном выше примере (для простоты).Вместо этого используйте List<EventListener<?>>, если вы хотите поддерживать несколько слушателей на класс.Кроме того, классы abobe создаются только по прототипу, требуются дополнительные приведения, но они являются типобезопасными, поскольку универсальный тип Event<T> всегда ссылается на тот же класс, что и getEventClass().

Пример использования:

  • Для вашего мероприятия: new Event(data, GuiChangedData.class);
  • Связанный слушатель:

    public class GuiChangedListener implements EventListener<GuiChangedData> {
        // ...
    }
    

Если вам нужна дополнительная информация, не стесняйтесьспросить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...