Язык программирования Java Дмитриев Андрей Владиславович 2007
Наблюдатель (Observer) Определяет между объектами зависимость типа один-ко-многим так, что при изменении состояния одного объекта, все зависящие от него объекты получают об этом оповещение.
Наблюдатель class LogConsole extends Terminal{ private color = Color.BLACK; void setColor(Color c){ this.color = c; } Класс LogConsole должен изменять цвет вывода сообщений в зависимости от их приоритета, определяемого и устанавливаемого классом MainWindow.
Наблюдатель (cont.) class MainWindow{ LogConsole logConsole = LogConsole.create(); void userAction(Action a){ if (a.getLevel() == Level.isCritical()) { logConsole.setColor(Color.RED); } Данный класс может напрямую изменять состояние подчиненного объекта при изменении ситуации:
Наблюдатель (cont.) class MainWindow{ … //все поля и методы остаются IntrusionDetector id = IntrusionDetector.get(); void userAction(Action a){ … //все прошлые действия остаются if (a.getLevel() == Level.isIntrusion()) { id.alarm(); } У нас появился еще один класс, заинтересованный в типе действия пользователя – IntrusionDetector.
Наблюдатель (cont.) public interface ActionObserver{ void actionHappen(Action a); } Для большей структурированности имеет смысл выделить круг классов, заинтересованных в данном типе событий:
Наблюдатель (cont.) class LogConsole extends Terminal implements ActionObserver { void actionHappen(Action a){ if (a.getLevel() == Level.isCritical()) { setColor(Color.RED); } Теперь класс LogConsole и IntrusionDetector можно причислить к кругу заинтересованных:
Наблюдатель (cont.) class IntrusionDetector implements ActionObserver{ public void actionHappen(Action a){ if (a.getLevel() == Level.isIntrusion()) { alarm(); } Аналогично с классом IntrusionDetector:
Наблюдатель (cont.) class MainWindow{ ActionObserver []observers = new ActionObserver [10]; void userAction(Action a){ //обход массива for (…) { observers[i].actionHappen(a); } //заметим, что вся логика по обработке //события переместилась в конкретные классы. } Класс MainWindow должен хранить ссылки на все классы, заинтересованные в событиях:
Наблюдатель (cont.) class MainWindow{ ActionObserver []observers = new ActionObserver [10]; … public void addActionObserver(ActionObserver aa){ observers[last++] = aa; } public void removeActionObserver(ActionObserver aa){ //удаление объекта из массива } Класс MainWindow должен предоставлять интерфейс для пополнения списка объектов, заинтересованных в данных сообщениях:
Пример реализации наблюдателя в JDK import java.awt.event.* … List list = new List(); il = new ItemListener(){ //метод будет вызываться каждый раз при //изменении состояния списка public void itemStateChanged(ItemEvent e){ System.out.println(event + e); } }; list.addItemListener(il); Наблюдатель – любой класс, реализующий один или несколько слушателей: MouseListener, ItemListener, FocusListener, и т.д.
Наблюдатель (иллюстрация)
Наблюдатель (выводы) Позволяет избежать циклических опросов состояния. Возможность реализовать неограниченное число наблюдателей.