Класи Observer / Observable

Типи Observer / Observable надають протокол, відповідно до якого довільну кількість обєктів-спостерігачів Observer отримують повідомлення про

небудь зміни або події, що відносяться до довільного кількості обєктів Observable Обєкт Observable проводиться від підкласу Observable, завдяки чому можна вести список обєктів Observer, Повідомляти про зміни в обєкті Observable Всі обєкти-спостерігачі, що входять до списку, повинні реалізовувати інтерфейс Observer Коли із спостережуваним обєктом відбуваються зміни, заслужи

вающие уваги, або трапляються деякі події, які становлять інтерес для Observer, викликається метод notifyObservers обєкта Observable, який звертається до методу update для кожного з обєктів Observer Метод update інтерфейсу Observable виглядає наступним чином:

public abstract void update(Observable obj, Object arg)

Метод викликається, коли обєкт Observable повинен повідомити спостерігачам про зміну або деяке подію Параметр arg дає можливість передачі довільного обєкта, що містить опис зміни або події в обєкті Observer

Механізм Observer / Observable проектувався з розрахунком на універсальність Кожен клас Observable сам визначає, коли і за яких обставин повинен викликатися метод update обєкта Observer

Клас Observable реалізує методи для ведення списку обєктів Observer, для установки прапора, який повідомляє про зміну обєкта, а також для виклику методу update будь-якого з обєктів Observer Для ведення списку обєктів Observer використовуються такі методи:

public synchronized void addObserver(Observer o)

Додає аргумент o типу Observer до списку обєктів-спостерігачів public synchronized void deleteObserver(Observer o)

Видаляє аргумент o типу Observer зі списку обєктів-спостерігачів public synchronized void deleteObservers()

Видаляє всі обєкти Observer зі списку спостерігачів public synchronized int countObservers()

Повертає кількість обєктів-спостерігачів

Наступні методи сповіщають обєкти Observer про зміни, що:

public synchronized void notifyObservers(Object arg)

Повідомляє всі обєкти Observer про те, що із спостережуваним обєктом щось сталося, після чого скидає прапор зміни обєкта Для кожного обєкта-спостерігача, що входить до списку, викликається його метод update, першим параметром якого є обєкт Observable, а другий – arg

public void notifyObservers()

Еквівалентний notifyObservers (null)

Наведений нижче приклад показує, як протокол Observer / Observable може застосовуватися для спостереження за користувачами, зареєстрованими в системі Спочатку визначається клас Users, що розширює Observable:

import javautil*

public class Users extends Observable {

private Hashtable loggedIn = new Hashtable()

public void login(String name, String password)

throws BadUserException

{

/ / Метод збуджує виняток BadUserException if ( PasswordValid (name, password)

throw new BadUserException(name)

UserState state = new UserState(name) loggedInput(name, state) setChanged()

notifyObservers(state)

}

public void logout(UserState state) { loggedInremove(statename()) setChanged() notifyObservers(state)

}

// ..

}

Обєкт Users містить список активних користувачів і для кожного з них заводить обєкт UserState Коли хто-небудь з користувачів входить в систему або припиняє роботу, то всім обєктам Observer передається його обєкт UserState Метод notifyObservers розсилає повідомлення спостерігачам лише у разі зміни стану обєкта, що спостерігається, так що ми повинні також викликати метод setChanged для Users, інакше notifyObservers нічого не зробить Крім методу setChanged, існує ще два методи для роботи з прапором зміни стану: clearChanged позначає обєкт Observable як незмінних, а hasChanged повертає логічне значення прапора

Нижче показано, як може виглядати реалізація update для обєкта Observer, постійно стежить за складом зареєстрованих користувачів:

import javautil*

public class Eye implements Observer { Users watching

public Eye(Users users) { watching = users watchingaddObserver(this)

}

public void update(Observable users, Object whichState)

{

if (users = watching)

throw new IllegalArgumentException()

UserState state = (UserState)whichState

if (watchingloggedIn (state)) / / вхід в систему

addUser (state) / / Внести в список

else

}

}

removeUser (state) / / Видалити зі списку

Кожен обєкт Eye спостерігає за конкретним обєктом Users Коли користувач входить в систему або припиняє роботу, обєкт Eye сповіщається про це, оскільки в його конструкторі викликається метод addObserver для обєкта User, в якому обєкт Eye вказується в якості обєкта-спостерігача При виклику методу update відбувається

перевірка на правильність параметрів і зміна виведеної інформації залежно від того, увійшов чи даний користувач в систему або вийшов

Перевірка того, що відбувається з обєктом UserState, в даному випадку виконується

просто Втім, її можна уникнути – для цього слід замість самого обєкта UserState передавати обєкт-оболонку, який описує, що і з ким відбувається Такий варіант виглядає наочніше і полегшує додавання нових можливостей без порушення існуючого програмного коду

Механізм Observer / Observable частково нагадує механізм wait / notify для потоків, описаний на стор, проте він відрізняється більшою гнучкістю і меншою кількістю обмежень Механізм потоків гарантує, що синхронний доступ захистить програму від небажаних ефектів багатозадачності Механізм спостереження дозволяє організувати між учасниками будь-який звязок, не залежну від використовуваних потоків В обох механізмах передбачений постачальник інформації (Observable і обєкт, що викликає notify) та її споживач (Obs e rver і обєкт, що викликає wait), однак

вони задовольняють різні потреби Використовуйте wait / notify, коли механізм повинен враховувати специфіку потоків, і Observer / Observable для більш загальних випадків

Вправа 126

Створіть реалізацію інтерфейсу Attributed, в якій механізм Observer / Observable

використовується для повідомлення спостерігачів про зміни, що відбуваються c обєктами

Джерело: Арнольд К, Гослінг Д – Мова програмування Java (1997)

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*