Статьи

Учебное пособие по Наблюдателю с примерами Java

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

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

Refcard Designs Patterns
Для лучшего обзора самых популярных шаблонов дизайна, лучше всего начать с Refcard Designs Patterns от DZone .

Наблюдатель в реальном мире

Прежде чем мы углубимся в теорию и код, лежащий в основе Observer, давайте рассмотрим пример из реальной жизни, такой как RSS-каналы. Когда я хочу получать обновления из определенного канала, я добавляю его в программу чтения каналов. Каждый раз, когда RSS-лента обновляется, она автоматически появляется в моем ридере. Это паттерн «Наблюдатель в действии», отношение издатель / подписчик с одним источником, имеющим много подписчиков. 

Образец Наблюдателя

Из всех существующих шаблонов проектирования Observer, вероятно, уже использовался вами, даже если вы об этом не знали. Шаблон Observer является золотым стандартом в отделении — разделении объектов, которые зависят друг от друга.

Наблюдатель известен как поведенческий паттерн, так как он используется для формирования отношений между объектами во время выполнения. Определение, приведенное в оригинальной книге «Банды четырех» по шаблонам проектирования, гласит: 

Определите зависимость «один ко многим» между объектами, чтобы при изменении состояния одного объекта все его иждивенцы уведомлялись и обновлялись автоматически.

Давайте посмотрим на классическую диаграмму определения наблюдателя:

Идея, лежащая в основе шаблона, проста — один из нескольких наблюдателей интересуется состоянием субъекта и регистрирует свой интерес у субъекта, прикрепляя себя. Когда что-то меняется в нашей теме, что может заинтересовать наблюдателя, отправляется уведомление , которое вызывает метод обновления у каждого наблюдателя.
Когда Наблюдатель больше не интересуется состоянием Субъекта, он может просто отключиться . Следующая диаграмма последовательности иллюстрирует процесс регистрации и уведомления в действии.

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

Где бы я использовал этот шаблон?

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

Вы видели и, вероятно, использовали Observer много раз, если вы занимались программированием пользовательского интерфейса, особенно в Swing. Вся концепция слушателей основана на этом шаблоне. Слушатель событий является самым популярным, где вы регистрируете ActionListener в элементе управления UI, например, кнопке, и реагируете на события действия с помощью метода actionPerformed . В этом случае ActionListener — это Observer, а кнопка — ваш объект. Когда кнопка меняет состояние, вы можете реагировать, если хотите, в своем методе actionPerformed. 

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

Так как это работает в Java?

В то время как некоторые шаблоны требуют, чтобы вы определяли интерфейсы, которые заставляют шаблон работать, Observer — это тот случай, когда Java уже сделала всю работу за вас в пакете java.util.

Небольшое отличие от классического определения заключается в том, что Observable используется вместо Subject и реализуется как класс, а интерфейс Observer остается тем же. Давайте посмотрим на реализацию шаблона с реальным примером. В нашем примере субъектом будет DataStore с классом Screen в качестве наблюдателя.

Во-первых, давайте сделаем наш класс DataStore видимым, расширив класс java.util.Observable . Это означает, что в нашем хранилище данных есть все методы и функциональные возможности, чтобы сделать его субъектом в соответствии с нашим шаблоном. 

import java.util.Observable;
public class DataStore extends Observable {
  private String data;
  public String getData() {
    return data;
  }
  public void setData(String data) {
    this.data = data;
    //mark the observable as changed
    setChanged();
  }
}

Вы заметите, что мы вызвали метод setChanged () объекта Observable. Это необходимо для того, чтобы звонок уведомлял наблюдателей об отправке обновления. Без этого набора Observable не увидит причин для отправки обновления. 

Далее, давайте создадим нашего Обозревателя. Чтобы сделать это, все, что нам нужно сделать, это реализовать интерфейс Observer, который заставляет нас написать метод обновления, чтобы иметь дело с изменениями в состоянии Observable. 

public class Screen implements Observer {
  @Overridepublic
  void update(Observable o, Object arg) {
    //act on the update
  }
}

Добавить наш экран в качестве наблюдателя в хранилище данных очень просто: 

Screen screen = new Screen();
DataStore dataStore = new DataStore();
//register observer
dataStore.addObserver(screen);

Когда данные изменяются, мы хотим уведомить всех наблюдателей об этом объекте. Для этого нам просто нужно вызвать метод notifyObservers, когда мы хотим отправить обновление 

//send a notification
dataStore.notifyObservers();

Как видите, это действительно простой для понимания шаблон, и его еще проще использовать благодаря реализации шаблона на Java. 

Остерегайтесь недостатков

Как и в случае с любым другим фрагментом кода, вы должны быть осторожны при использовании шаблона Observer. У Мартина Фаулера есть хороший список ошибок для наблюдателя. В своей статье он упоминает, что может быть трудно увидеть путь через код, если вы не отлаживаете. Таким образом, вы должны быть осторожны, чтобы не иметь цепочки наблюдателей (наблюдатели, действующие как субъекты). Кроме того, следите за утечками памяти, поскольку субъект будет хранить ссылку на наблюдателя, если он не отменил регистрацию. 

Наслаждайтесь всей серией «Design Patterns Uncovered»:

Образцы творчества

Структурные паттерны

Поведенческие образцы