События вызывают цепную реакцию - PullRequest
5 голосов
/ 19 августа 2011

Я использую среду на основе Eclipse RCP, которая страдает от неэффективной модели событий.В частности, события, испускаемые элементами управления, часто «каскадные».Например, элемент управления будет выдавать событие COLOR_CHANGED, в результате чего родительский композит распространяет это событие на элементы управления одного уровня, которые, в свою очередь, решат выдать свои собственные события COLOR_CHANGED (в ответ на исходное событие), что приведет к цепочкереакция сортов.Я профилировал приложение, подняв более 100 000 событий, чтобы отобразить простую форму.Честно говоря, я не понимаю, как он не переполняет стек.

Итак, я ищу технику или шаблон проектирования, который предотвращает или уменьшает такое каскадное поведение.У меня было несколько идей, но это не может быть новой проблемой;уже существует «лучшая практика» для ориентированного на события проектирования.

Мои идеи:

  • События работают как трассировка стека, поэтому новые события связаны сих причина.Это позволяет слушателям игнорировать события, которые произошли от них самих.Однако это сильно усложняет мою модель событий (и было бы утомительно переносить стандартные события SWT).Не говоря уже о том, что существуют допустимые сценарии использования, в которых вы могли бы на самом деле хотеть такого поведения.
  • Центральный «насос событий» используется для вызова событий.Если событие имеет тот же источник и полезную нагрузку, что и ранее возникшее событие в течение последних n миллисекунд, оно отбрасывается.Мы надеемся, что это будет иметь допинговый эффект и предотвратит каскадные события.Очевидно, я не могу контролировать, как возникают события SWT / RCP, но это не моя главная задача.
  • События должны быть напечатаны.Это кажется шагом назад, но я думаю, что более мелкозернистые события помогут производительности.Например, ValidationFailedEvent, а не универсальный Event, который каждый обрабатывает (а затем должен опросить его состояние, чтобы определить тип события).

Спасибо, что нашли время, чтобы прочитать о моей проблеме.Все советы / предложения приветствуются.

РЕДАКТИРОВАТЬ : Благодаря pablosaraiva я прочитал о Цепочка ответственности и теперь имею следующую идею:

  • События предоставляют свойство isHandled, которое, если установлено в true, будет препятствовать распространению события.Это должно работать, когда понимается область события, но не поможет, если событие не может быть «обработано» одним элементом управления.

1 Ответ

1 голос
/ 19 августа 2011

Я играл с разными подходами к этому на протяжении многих лет. Фундаментальная вещь, которую вы можете сделать, чтобы исправить это, - это иметь модели, генерирующие события, только если они действительно меняются. Это делает модели немного более сложными для каждого класса в модели, но это единственный способ, которым мне удалось заставить эту парадигму работать.

Например

public void setColor(Color c)
{
   setBackground(c);
   notify(new ColorChangedEvent(this, c));
}

станет

public void setColour(Color c)
{
    if (!getBackground().equals(c))
    {
       setBackground(c);
       notify(new ColorChangedEvent(this, c));
    }
}

Стандартные классы Observable в java поддерживают это с помощью метода setChanged ().

Немного более простой способ реализовать это (но IMHO не так хорошо) - заставить 'notify' отключить прослушивание до тех пор, пока не закончится уведомление. То есть уведомление выглядит как

private iAmNotifying;
public void notify(Event e) 
{ 
    if (!iAmNotifying)
    {
        iAmNotifying = true;
        doTheActualNotification(e);
        iAmNotifying = false;
    }
}

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

...