Уведомление наблюдателей от вложенных структур

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

Модель данных представлена ​​вложенной структурой:

Model
- Node
  - Leaf
  - Leaf
- Node
  - Leaf

Каждый элемент наследуется от общего абстрактного базового класса (StructuredNode).

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

public abstract class Base {

  private static Map<IObserver> observers;


  protected synchronized void internalSubscribe(final IObserver observer) {
    observers.add(observer);
  }

  protected synchronized void notifyObservers(final Base obj) {
    for (IObserver observer : observers)
      observer.changed(obj);
  }

  // .. other base class operations
}

В этой реализации только Model будет предлагать открытый метод подписки, который внутренне делегирует защищенному методу internalSubscribe базового класса. В то же время каждая производная базового класса может отправлять уведомление об изменении, например:

// Perform some operations that change the object's internal state
// ...
// Then notify all observers
notifyObservers(this);

Это хорошая или плохая практика (с использованием статического списка наблюдателей)? Есть мнения по этому поводу? Есть ли альтернативные решения?

1 ответ

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

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

Конечно, все это может не применяться в вашем случае. Если вы знаете, что в вашем приложении не будет более одной модели этого класса, тогда вы вполне можете использовать это решение.

В любом случае, требование наличия только Модели с открытым методом подписки не должно ограничивать вас использованием контейнера статического наблюдателя для совместного использования всеми экземплярами Модели. Как вы сказали, есть другой способ. Маршрутизация уведомлений вверх по иерархии - ИМХО правильный путь.

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

Другие вопросы по тегам