Общий EventManager - застрял после 3 строк кода :-)

1

Я так близок, но я не обнимаю голову.

Я пытаюсь создать диспетчер событий в Java (Android) с файлами по умолчанию, например, регистрировать события, создавать события и т.д....

Я хочу, чтобы это было "общим" таким образом, что я могу написать что-то вроде этого:

StringChangedEvent event 
       = evManInst.Register<StringChangedEvent>(new StringChangedEvent());
event.Publish("Hello");

И в другом классе

StringChangedEvent event 
       = evManInst.Register<StringChangedEvent>(new StringChangedEvent());
event.Subscribe(this)

Конечно, экземпляр должен быть одним и тем же. Мне нужно передать объект, потому что я наклоняю новый T() - но, возможно, я делаю что-то действительно злое с дженериками здесь :-)

Если вы прочитали реализацию моего EventManager, первая линия возврата не будет компилироваться из-за несовместимых типов. Как я могу это решить? Самое смешное, если вы посмотрите на код, все это довольно хорошо относится к типам, нет ничего, что может пойти не так (на мой взгляд).

Еще один момент: я не хочу создавать общий EventManager<StringChangedEvent> потому что это ограничивает этот EventManager одним типом событий. И возвращение EventBase и кастинг это просто уродливо (но, возможно, единственный способ пойти?).

  public class EventManager
    {
        private HashMap<Class<EventBase>, EventBase> _registeredEvents 
          = new HashMap<Class<EventBase>, EventBase>();

        public<T extends EventBase> T Register(T instance)
        {
        if (_registeredEvents.containsKey(instance.getClass()))
        {
            return _registeredEvents.get(instance.getClass());
        }
        else
        {
            return instance;
        }
    }

}

РЕДАКТИРОВАТЬ Чтобы прояснить комментарий к ответу от Kaediil

EventManager x = new EventManager<TestEvent>();
EventManager x2 = new EventManager();

// Not OK
TestEvent t = x.Register(new TestEvent());

// OK (but I want MORE :-)
TestEvent t2 = (TestEvent)x.Register(new TestEvent());

// This to be exact, because then I can do something like this
TestEvent t2 = x.Register<TestEvent>(new TestEvent());

x.Register<TestEvent>(new TestEvent()).CallMethodOfTestEvent();
  • 0
    В чем ошибка компиляции?
  • 0
    Несовместимые типы. Он хочет, чтобы я возвратил T, и он, кажется, не понял, что экземпляр имеет тип T.
Показать ещё 1 комментарий
Теги:
generics
events

2 ответа

1
Лучший ответ

Следующий код должен делать то, что вы хотите:

import java.util.HashMap;

public class EventManager {

    private HashMap<Class<? extends EventBase>, EventBase> _registeredEvents
            = new HashMap<Class<? extends EventBase>, EventBase>();


    public <T extends EventBase> T Register(T event) {
        @SuppressWarnings("unchecked")
        Class<? extends T> eventType = (Class<? extends T>) event.getClass();

        if (_registeredEvents.containsKey(eventType)) {
            return eventType.cast(_registeredEvents.get(eventType));
        } else {
            _registeredEvents.put(eventType, event);
            return event;
        }
    }
}

class EventBase {}

class ChangeEvent extends EventBase {}

class Main {
    public static void main(String[] args) {
        EventManager em = new EventManager();
        ChangeEvent e = em.Register(new ChangeEvent());
    }
}

Компилятор жалуется на строку, следующую за @SuppressWarnings, но я думаю, что это должно быть правильно, и это просто магия компилятора вокруг getClass(), которая не справляется с этим правильно.

Проблема в вашем коде заключалась в том, что вы не можете получить что-то еще, кроме EventBase из HashMap<…, EventBase> потому что нет способа статически доказать, что это typeafe. Вы должны бросить куда-нибудь, и Class.cast позволяет вам сделать это при реализации метода. (Вы также можете использовать для T чтобы "заставить компилятор заткнуться", но это плохая идея, потому что это делает ClassCastExceptions случаться в коде, используя ваш API, а не там, где выполняется трансляция.)

  • 0
    О, я люблю эту страницу :-) Работает отлично, и мне даже не нужно <> для функции (это было моей ошибкой, в C # вы делаете это, и я только догадался о синтаксисе Java ...)
1

Попробуй это:

public class EventManager <T extends EventBase>{

private HashMap<Class<EventBase>, T > _registeredEvents 
= new HashMap<Class<EventBase>, T>();



public T Register( T instance)
{
    if (_registeredEvents.containsKey(instance.getClass()))
    {
        return  _registeredEvents.get(instance.getClass());
    }
    else
    {
        return instance;
    }
  }
}
  • 0
    Спасибо, но это только дает мне половину пути. Я знаю, что я стервозная маленькая девочка, но я хочу (t) работать, t2 слишком длинный :-) Смотрите выше отредактированный код в конце ... x или x2 не имеют значения, кстати.
  • 0
    @Christian: вам нужно объявить переменную (в вашем редактировании) как EventManager<TestEvent> x = new EventManager<TestEvent>(); не как необработанный тип.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню