Подводные камни обработки событий в Java - PullRequest
2 голосов
/ 15 декабря 2009

Я работаю над программой, которой нужен объект Java, чтобы иметь событие. Я довольно знаком с тем, как это работает в C #, имея достаточно опыта, чтобы изучить подводные камни.

Какие подводные камни в работе с событиями в Java? Чем они отличаются от событий в C # 2.0?

Пример: объект изменил событие, чтобы запросить сохранение у объекта-владельца.

Примечание: Java 1.5

Связанный: Обработка событий C # (по сравнению с Java)

Ответы [ 5 ]

7 голосов
/ 15 декабря 2009

В Java нет встроенной концепции событий, поэтому лучше всего использовать варианты Шаблон наблюдателя .

3 голосов
/ 15 декабря 2009

В C # вы должны делать это, когда запускаете событие :

public event SomeDelegate MyEvent;

private void FireMyEvent(MyEventArgs args)
{
    var deleg = MyEvent;
    if (deleg != null) deleg(args);
}

... для защиты от одновременной модификации (в случае, если поток удаляет прослушиватель событий между вами, проверяющим нулевое значение MyEvent и вызывающим его) В Java вы бы вместо этого использовали CopyOnWriteArrayList, чтобы защитить себя от одновременного изменения:

private final CopyOnWriteArrayList<MyEventListener> listeners = 
    new CopyOnWriteArrayList<MyEventListener>();

private void fireMyEvent(MyEventArgs args){
    // Iteration is performed over a snapshot of the list, concurrent
    // modifications from other threads are invisible to the iterator
    // and will not cause ConcurrentModificationExceptions.
    for (MyEventListener listener : listeners)
        listener.eventOccurred(args);
}
1 голос
/ 15 декабря 2009

Как упоминалось ранее, в Java нет делегатов и событий , которые есть в C #. Но, учитывая, что это «обобщенная» реализация шаблона Observer (GoF), вы можете реализовать его самостоятельно.

В есть примеры страницы википедии о том, как реализовать шаблон с java.util.Observable и java.util.Observer. Общая идея состоит в том, чтобы позволить классам, которые реализуют Observer, подписаться на Observable класс.

Я обычно использую свою собственную реализацию, так как это чертовски легко сделать, поскольку вам нужно только создать интерфейс, объявляющий методы, которые "наблюдаемый" класс вызывает для своих зарегистрированных "наблюдателей". Вот простой пример наблюдаемого класса, который может зарегистрировать SimpleObserver объектов и выполнить с ними какое-то событие:

public class MyObservableClass {

    List<SimpleObserver> observers = new ArrayList<SimpleObserver>();

    /**
     * Registers the observer
     */
    public void addObserver(SimpleObserver observer) {
        observers.add(observer);
    }

    /**
     * Removes the registered observer (to be nice towards the
     * garbage collector).
     */
    public void removeObserver(SimpleObserver observer) {
        observers.remove(observer);
    }

    /**
     * Notifies the observers with the given data
     */
    private void notifyObservers(String data) {
        for(SimpleObserver o : observers) {
            o.onEvent(data);
        }
    }

    public void doSomething() {
        // Do some stuff
        String data = "Waffles and pwnies";
        // Notify the observers that something happened.
        notifyObservers(data)
    }

}

… а вот простой интерфейс наблюдателя.

public interface SimpleObserver {
    void onEvent(String data);
}

Это может показаться немного сложным, но преимущество в том, что классу Observable не нужно знать, какие именно объекты его «слушают» (именно поэтому наблюдателей иногда называют * 1028). * слушатели ). Это обеспечивает четкое разделение проблем между ними обоими. Наблюдатели должны зарегистрироваться для наблюдения.

Единственная «ошибка», о которой я могу подумать, это утечка памяти, которую этот шаблон может вызывать даже в управляемой памяти среде, такой как Java. Это из-за «эталонных островков» между Observers и Observables, которые запутают сборщик мусора и не попытаются удалить объекты из памяти. всегда хорошая идея удалить неиспользуемых наблюдателей .

1 голос
/ 15 декабря 2009

Java не имеет специальной концепции Event. Это реализовано через API по принципу Observable + Observer. Насколько я знаю, в спецификации Java нет выделенного лямбда-функционала API.

0 голосов
/ 15 декабря 2009

События строго зависят от контейнера в Java, и стандартная библиотека просто предоставляет обобщенный интерфейс (который обычно расширяется для конкретных требований).

Единственный «уловок» в отношении событий, которые, возможно, можно рассматривать в контексте Java (в целом), - это контейнеры Swing (Компонент) и диспетчеризация событий. Платформа свинга является однопоточной, и ожидается, что не будет использовать поток диспетчеризации событий (то есть обратный вызов) для выполнения вычислительно-интенсивной работы с высокой задержкой в ​​слушателе событий.

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