March
По просьбам читателей очередную статью о паттернах проектирования посвящу паттерну Observer (Наблюдатель). Этот шаблон проектирования также известен под именами Dependents (Подчиненные) и Publisher-Subscriber (Издатель-Подписчик).
Реализация данного паттерна используется для наблюдения за состоянием объектов в системе. Если состояние объектов изменяется в процессе их жизненного цикла, то Наблюдатель оповещает другие части системы об этих событиях.
В данной статье я попытаюсь как можно проще и понятнее рассказать об этом паттерне и привести пример программного кода на Java, реализующего Observer.
В каких случаях используется Наблюдатель?
- Если один объект должен передавать сообщения другим объектам, но при этом он не может или не должен знать об их внутреннем устройстве;
- В случае если при изменении одного объекта необходимо изменять другие объекты;
- Для предотвращения сильных связей между объектами системы;
- Для наблюдения за состоянием определенных объектов системы;
Наблюдаемый (observable) объект (а точнее субъект или subject) должен предоставлять интерфейс для регистрации и дерегистрации наблюдателей (listeners).
Ну а сами наблюдатели должны как минимум обладать открытым методом через который и будет происходить оповещение об изменении состояния субъекта. Этот метод часто называют notify.
Так как наблюдателей может быть достаточно много, для упрощения работы с ними можно использовать коллекцию (collection of observers). Приблизительно такой код я использую в этом случае:
public interface Observer {
void objectCreated(Object obj);
void objectModified(Object obj);
}
class EmptyObserver implements Observer {
public void objectCreated(Object obj) { }
public void objectModified(Object obj) { }
}
class Observers<T extends Observer> extends ArrayList<T> {
public void notifyObjectCreated(Object obj) {
for (Iterator<T> iter = (Iterator<T>) iterator(); iter.hasNext();)
iter.next().objectCreated();
}
public void notifyObjectModified(Object obj) {
for (Iterator<T> iter = (Iterator<T>) iterator(); iter.hasNext();)
iter.next().objectCreated();
}
}
Класс EmptyObserver может быть полезен в случае если у Наблюдателя достаточно большое количество notify методов. Тогда используя анонимные классы можно с легкостью создавать необходимые нам “узкоспециализированные” наблюдатели (те, у которых реализовано ограниченное количество методов) на лету:
Observers observers = new Observers();
observers.add(new EmptyObserver() {
public void objectCreated(Object obj) { /* реализация */ }
});
Далее, экземпляр класса Observers помещается в субъект за которым должно вестись наблюдение. Во всех местах кода, где происходит интересующее нас действие с классом-субъектом, добавляем соответствующий вызов notify метода у коллекции наблюдателей:
public class Subject {
Observers observers = new Observers();
private Object field;
public void setField(Object o) {
field = o;
observers.notifyObjectModified(this);
}
}
Кажется, основы осветил. Нюансы предлагаю обсуждать в комментариях.
Классический пример использования паттерна Observer - это классы из пакета Java Swing. В Swing паттерн Наблюдатель используется для организации слабой взаимозависимости между моделью и графическими объектами. Методы notify вызываются при изменении значений свойств модели и передают информацию в виджеты.
Кстати, очень рекомендую всем посмотреть исходный код Java Swing. Это действительно очень качественно спроектированная библиотека.
1 Comment »
RSS feed for comments on this post.
Спасибо! Доходчиво и понятно объяснил и показал *THUMBS_UP*