23 ноября 2008

Паттерн поведения Observer (наблюдатель)

Наблюдатель (Observer) - паттерн поведения объектов, устанавливающий систему оповещения объектами своих соседей в процессе их деятельности.
Известен также под именами: Dependents (подчиненные), Publish-Subscribe (издатель-подписчик).

В процессе функционирования и взаимодействия объектов системы нужно оповещать других участников по завершении какой-нибудь значимой операции. Конечно же, можно в каждый такой класс, производящий значимые действия добавлять обращение к этим всем другим заинтересованным объектам, но таким образом мы дублируем связи между объектами (система становится все менее и менее гибкой) – это еще и в разы затруднит последующую модификацию каких либо участников, т.к. необходимо будет перекомпилировать этот код обращения ко всем заинтересованных субъектам.
В этом случае очень подошло бы иметь такую структуру, в которой каждый участник, если он заинтересован в каких-либо событиях системы, мог бы самостоятельно «подписаться» на эти изменния независимо от других заинтересованных участникам – и, таким образом, получая уведомления об этих событиях – выполнять требуемые ответные действия.
В результате – не создается лишних связей: есть источник значимых действий, есть заинтересованные в фактах выполнения этих действий субъекты, никак не связанный друг с другом, количество которых при этом – также неограниченно.

Паттерн-наблюдатель описывает именно такой подход: определяет зависимость типа «один ко многим» между объектами таким образом, что при изменении состояния одного объекта все зависящие от него оповещаются об этом и автоматически обновляются.

Реализация паттерна поведения Наблюдатель (Observer).

/** Observer design pattern sample
*/

import java.util.ArrayList;
import java.util.List;

public class Child {
// --
List list = new ArrayList();
void addObserver(Observer o){
list.add(o);
}
void removeObserver(Observer o){
list.remove(o);
}
void notifyObservers(){
for (Observer o:list){
o.update();
}
}
// --
void childGrow(int newAge){
System.out.println("Age of child changed to " + newAge);
notifyObservers();
}
public static void main(String []s){
Child ot = new Child();
ot.childGrow(1);
ot.addObserver(new Food());
ot.addObserver(new Toys());
ot.addObserver(new Clothes());
ot.childGrow(3);
ot.removeObserver(new Food());
ot.childGrow(10);
ot.removeObserver(new Toys());
ot.childGrow(15);
ot.addObserver(new Food());
ot.childGrow(20);
ot.removeObserver(new Food());
ot.removeObserver(new Clothes());
ot.childGrow(25);
}
}

interface Observer {
void update();
}

abstract class BaseObserver implements Observer {
public boolean equals(Object obj) {
return this.getClass().equals(obj.getClass());
}
}

class Clothes extends BaseObserver {
public void update() {
System.out.println("Change childs' clothes");
}
}

class Toys extends BaseObserver {
public void update() {
System.out.println("Change childs' toys");
}
}

class Food extends BaseObserver {
public void update() {
System.out.println("Change childs' food");
}
}


Итак, у нас есть класс Child , который описывает модель ребёнка, основное действие - ребёнок растёт : childGrow, и в зависимости от возвраста ребёнка необходимо менять одежду, еду, игрушки - эти сущности описываются классами Clothes, Food, Toys соответственно. Эти три сущности реалиузют интерфейс Observer через класс BaseObserver.
После создания экземпляра класса ребёнка мы можем добавить или удалить специфических наблюдателей, и при достижении ребёнком какого то возраста (вызов childGrow) автоматически произойдёт обновление зарегистрированных в это время слушателей.


Источники:
Ппаттерн наблюдатель
Observer pattern
Speaking on the Observer pattern

Комментариев нет: