Язык Jаvа обеспечивает готовую для использования реализацию паттерна «Наблюдатель». Разработчики легко могут реализовать этот паттерн с помощью интерфейса Observer и расширения класса Observable.
Первое, что нам необходимо сделать — это создать класс, расширяющий класс Observable. В следующем примере когда новостное агентство оповещает несколько типов подписчиков в момент публикации нового материала. Подписчик может добавить собственное поведение после получения обновления.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
// Новостное агентство (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.
1 2 3 4 5 |
// Интерфейс Publisher package com.devchronicles.observer; public interface Publisher {} |
Далее нам необходимо создать класс для наблюдения за изменениями NewsAgency. Наблюдатель должен реализовывать интерфейс Observer, как показана в следующем примере кода:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// Конкретный наблюдатель 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 и создать несколько новостных материалов.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// Создание наблюдателя и субъекта NewsAgency newsAgency = new NewsAgency(); RadioChannel radioChannel = new RadioChannel(); // Регистрация наблюдателя на субъекте newsAgency.register(radioChannel); // Добавление новостных заголовков newsAgency.addNews("Месси побил рекорд Лиги Чемпионов"); newsAgency.addNews("Россия примет чемпионат мира по футболу 2018"); newsAgency.addNews("На Марсе приземлился робот"); |
Вывод в консоли будет примерно следующим:
1 2 3 |
Месси побил рекорд Лиги Чемпионов Россия примет чемпионат мира по футболу 2018 На Марсе приземлился робот |
Заметьте, что вы можете регистрировать много наблюдателей на newsAgency и получать с их помощью обновления. Например, можно зарегистрировать наблюдатель TVChannel или InternetNewsChannel для получения обновлений от newsAgency.
Помимо этого, у вас могут быть другие Publisher (или любые иные типы объектов, реализующие Observable }, выдающие обновления любому наблюдателю, пожелавшему зарегистрировать себя для получения новостей. Эти наблюдатели могут осуществлять проверку типа Observable и обрабатывать обновления в соответствии с источником.
Один существенный недостаток подобной реализации паттерна «Наблюдатель» в том, что нам приходится расширять класс Observable. Это принуждает использовать иерархию классов, которая может быть нежелательной. Поскольку вы не можете расширить сразу несколько классов в мире единичного наследования языка Jаvа, такой способ реализации паттерна «Наблюдатель» ограничивает проектирование наследования.
Вы не можете добавить поведение класса Observable к существующему классу, который уже расширяет другой базовый класс, ограничивая тем самым потенциал его многократного использования. Но не отчаивайтесь. Вы можете реализовать паттерн «Наблюдатель» «вручную», без использования внутренних интерфейсов Observer и Observablе.