Общее наследование в Java - PullRequest
       15

Общее наследование в Java

3 голосов
/ 13 сентября 2010

У меня есть абстрактный класс AbstractEvent и некоторые «реальные» классы, расширяющие его.Я хочу создать абстрактный класс AbstractListener с методом process(??? event), чтобы неабстрактные классы, расширяющие AbstractListener, требовали, чтобы хотя бы один метод принимал класс, расширяющий AbstractEvent.Это возможно?

Ответы [ 2 ]

16 голосов
/ 13 сентября 2010

У вас уже есть название нужного вам механизма - generics !

Сначала создайте свой класс событий:

abstract class AbstractEvent {
    // Insert fields/methods common for all events here
}

Ничего странного в этом нет,Затем создайте параметризованный класс / интерфейс прослушивателя и присвойте его параметру типа верхнюю границу для класса объекта вашего события:

interface Listener<T extends AbstractEvent> {
    void process(T event);
}

Теперь вы можете продолжать создавать свои определенные классы событий:

class PonyEvent extends AbstractEvent {
    // Pony-specific stuff goes here
}

И, ну, это должно быть почти все, что вам нужно.Продолжайте и реализуйте ваши классы слушателей:

class LoggingPonyListener implements Listener<PonyEvent> {
    @Override
    public void process(PonyEvent event){
        System.out.println("Pony event occurred: " + event);
    }
}

Теперь у вас может возникнуть желание написать общий класс диспетчеризации событий, подобный этому:

class EventDispatcher<T extends AbstractEvent> {
    private final List<Listener<T>> listeners =
        new CopyOnWriteArrayList<Listener<T>>();
    public void addListener(Listener<T> listener) {
        listeners.add(listener);
    }
    public void dispatchEvent(T event) {
        for (Listener<T> listener : listeners) 
            listener.process(event);
    }

}

Выглядит довольно мило, а?Вы можете делать что-то вроде этого:

EventDispatcher<PonyEvent> dispatcher = new EventDispatcher<PonyEvent>();
dispatcher.add(new LoggingPonyListener());
dispatcher.dispatchEvent(new PonyEvent());

Совершенно мило, мы можем просто использовать этот материал, а затем, когда мы его используем, просто продолжать его повторное использование .Хотя есть одна проблема.Предположим, у вас есть умный разработчик, которому нужен супер-простой слушатель, который на самом деле ничего не делает с объектом события, а просто печатает указанное сообщение всякий раз, когда происходит событие.

Не совсем учитывая ваш класс EventDispatcher, это было написано так:

class DebugListener implements Listener<AbstractEvent> {
    private final String msg;
    public DebugListener(String msg) { this.msg = msg; }
    @Override
    public void process(AbstractEvent event){
        System.out.println(msg);
    }
}

Это должно быть многоразово, верно?Нет, это не сработает:

EventDispatcher<PonyEvent> dispatcher = new EventDispatcher<PonyEvent>();
dispatcher.add(new DebugListener("pony event"));

, потому что DebugListener - это Listener<AbstractEvent>, а не Listener<PonyEvent>.Чтобы решить эту проблему, можно использовать нижнюю границу для типа параметра:

class EventDispatcher<T extends AbstractEvent> {
    private final List<Listener<? super T>> listeners =
        new CopyOnWriteArrayList<Listener<? super T>>();
    public void addListener(Listener<? super T> listener) {
        listeners.add(listener);
    }
    public void dispatchEvent(T event) {
        for (Listener<? super T> listener : listeners) 
            listener.process(event);
    }

}

Это дает вам поведение, к которому вы стремитесь: точно так же, как вы можете отправить PonyEvent на processметод Listener<AbstractEvent> (поскольку PonyEvent является AbstractEvent), теперь вы можете использовать класс диспетчера событий, параметризованный с типом, для запуска слушателей, параметризованных одним из его супертипов.

0 голосов
/ 13 сентября 2010
public abstract class AbstractListener {
    public abstract void process(AbstractEvent event...);
}

Попробуйте это.Это создает абстрактный класс с именем AbstractListener, который имеет один абстрактный метод, который принимает одно или несколько абстрактных событий.Если вам абсолютно необходимо всегда иметь одно событие, вы можете попробовать что-то подобное (хотя я не могу вспомнить, технически ли это возможно):

public abstract class AbstractListener {
    public abstract void process(AbstractEvent event1, AbstractEvent otherEvents...);
}

Надеюсь, что это поможет.

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