Язык Jаvа обеспечивает готовую для использования реализацию паттерна "Наблюдатель". Разработчики легко могут реализовать этот паттерн с помощью интерфейса Observer и расширения класса Observable.
Первое, что нам необходимо сделать - это создать класс, расширяющий класс Observable. В следующем примере когда новостное агентство оповещает несколько типов подписчиков в момент публикации нового материала. Подписчик может добавить собственное поведение после получения обновления.
// (NewsAgency). Observable |
|
|
|
package com.devchronicles.observer |
|
|
|
import java.util.ArrayList; |
|
import java.util.List; |
|
import java.util.Observable; |
|
import java.util.Observer; |
|
|
|
public class NewsAgence extends Observable implements Publisher { |
|
|
|
private List<Observer> channels = new ArrayList<>(); |
|
|
|
public void addNews(String newsItem) { |
|
|
|
for(Observer outlet: this.channels) { |
|
|
|
outlet.update(this, newsItem); |
|
|
|
} |
|
|
|
} |
|
|
|
public void register(Observer outlet) { |
|
|
|
channels.add(outlet); |
|
|
|
} |
|
|
|
} |
Следующий код программы обеспечивает интерфейс для "публикации" класса Observable.
// Publisher |
|
|
|
package com.devchronicles.observer; |
|
|
|
public interface Publisher {} |
Далее нам необходимо создать класс для наблюдения за изменениями NewsAgency. Наблюдатель должен реализовывать интерфейс Observer, как показана в следующем примере кода:
// |
|
|
|
package com.devchronicles.observer; |
|
|
|
import java.util.Observable; |
|
import java.util.Observer; |
|
|
|
public class RadioChannel implements Observer { |
|
|
|
@Override |
|
public void update(Observable agency, Object newsItem) { |
|
|
|
if(agency instanceof Publisher) { |
|
|
|
System.out.println((String) newsItem); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
Наконец, вы должны зарегистрировать наблюдатель RadioChannel на наблюдаемом NewsAgency и создать несколько новостных материалов.
// |
|
|
|
NewsAgency newsAgency = new NewsAgency(); |
|
RadioChannel radioChannel = new RadioChannel(); |
|
|
|
// |
|
|
|
newsAgency.register(radioChannel); |
|
|
|
// |
|
|
|
newsAgency.addNews(" "); |
|
newsAgency.addNews(" 2018"); |
|
newsAgency.addNews(" "); |
Вывод в консоли будет примерно следующим:
|
|
2018 |
|
|
Заметьте, что вы можете регистрировать много наблюдателей на newsAgency и получать с их помощью обновления. Например, можно зарегистрировать наблюдатель TVChannel или InternetNewsChannel для получения обновлений от newsAgency.
Помимо этого, у вас могут быть другие Publisher (или любые иные типы объектов, реализующие Observable }, выдающие обновления любому наблюдателю, пожелавшему зарегистрировать себя для получения новостей. Эти наблюдатели могут осуществлять проверку типа Observable и обрабатывать обновления в соответствии с источником.
Один существенный недостаток подобной реализации паттерна "Наблюдатель" в том, что нам приходится расширять класс Observable. Это принуждает использовать иерархию классов, которая может быть нежелательной. Поскольку вы не можете расширить сразу несколько классов в мире единичного наследования языка Jаvа, такой способ реализации паттерна "Наблюдатель" ограничивает проектирование наследования.
Вы не можете добавить поведение класса Observable к существующему классу, который уже расширяет другой базовый класс, ограничивая тем самым потенциал его многократного использования. Но не отчаивайтесь. Вы можете реализовать паттерн "Наблюдатель" «вручную», без использования внутренних интерфейсов Observer и Observablе.
У меня только один вопрос: зачем вообще экстендить Observable, если update у Observer вы все равно вручную вызываете? Считай все равно ручная имплементация.
Чтобы update сам вызвался, надо было в Observable делать
setChanged();
notifyObservers(newsItem);