Главная » Java » Observer/Observable

0

 

   Пара типов предоставляет средства отслеживания произвольным множеством объектов Observer всех изменений и событий, которые затрагивают произвольное число объектов Observable. Объект класса, производного от Observable, содержит методы, позволяющие поддерживать список объектов типа Observer, которым следует "знать" обо всех "происшествиях", касающихся объекта Observable. Все объекты такого списка должны относиться к классам, реализующим интерфейс Observer. Когда объект Observable подвергается изменению или встречается с событием, заслуживающим "внимания" со стороны объектов Observer, он вызывает собственный метод notifyObservers, который, в свою очередь, обращается к методу update каждого из "заинтересованных" объектов Observer.

   В составе интерфейса Observer предусмотрен единственный метод, рассмотренный ниже.

 public void update(Observable obj,  Object arg)

Метод вызывается в том случае, когда объект obj класса Observable обладает информацией об изменении или событии, на которое надлежит отреагировать. Параметр arg позволяет передать объекту Observer произвольный объект, содержащий описание происшедшего.

   Механизм, поддерживаемый типами , по умолчанию реализован в самом общем виде. Каждому классу, производному от Observable, позволено самостоятельно определять круг тех обстоятельств, возникновение ко торых приводит к вызову методов update соответствующих объектов Observe

Объект Observable поддерживает флаг изменен (changed), который устанавливается методами производного класса в том случае, когда случается нечто, достойное внимания.

 

protected void setChanged()

Помечает    текущий    объект    Observable    признаком    изменен    (метод hasChanged, описанный ниже, теперь вернет значение true), но уведомления (notify) объектам Observer не посылает.

 protected void clearChangedO

Аннулирует   признак   изменен  для   текущего   объекта   Observable   (метод hasChanged теперь вернет значение false); тот же эффект косвенным образом достигается при рассылке объектам Observer уведомления об изменении (за подробностями обращайтесь к описанию методов notifyObservers).

public void haschanged()

Возвращает текущее значение признака изменен.

 

   При внесении изменения или возникновении события, достойных внимания, объект Observable обязан вызвать собственный метод setChanged, а затем уведомить все соответствующие объекты Observer посредством одного из методов, описанных ниже.

public void notifyObservers(Object arg)

Посылает всем объектам Observer из ранее созданного списка уведомление о том, что произошло событие, на которое следует отреагировать, а затем присваивает флагу изменен значение false. Вызывает метод update каждого из объектов Observer списка, передавая ссылку на текущий объект Observable первым параметром, а объект arg — вторым.

 public void notifyObservers()

   Метод аналогичен предыдущему при условии notifyObservers (null).

Следующие методы класса Observable позволяют создавать и обновлять список "заинтересованных" объектов Observer.

 public void addobserver(Observer о)

Добавляет объект о в список объектов Observer, если это не было сделано раньше.

public void deleteobserver(Observer o)

                 Удаляет объект о из списка объектов Observer.

public void deleteObservers()

                  Удаляет все объекты из списка объектов Observer.

 public int countobservers()

   Возвращает количество объектов в списке объектов Observer.

Методы     объекта     Observable      используют     механизм     синхронизации (synchronization) для обеспечения согласованных действий при одновременном доступе к объекту со стороны нескольких потоков вычислений. Например, один поток может предпринять попытку добавить в список объектов Observer новый объект, другой   в то же самое время — удалить объект из списка, а третий —  снабдить текущий объект Observable признаком изменен. Хотя без синхронизации не обойтись при поддержке списка объектов Observer и состояния изменен объекта Observable, блокировки не должны устанавливаться при вызове методов   update   объектов   Observer,   поскольку  это   чревато   возникновением взаимоблокировки (deadlock). В реализациях методов notifyObservers, преду, смотренных по умолчанию, перед вызовом методов update предполагается создание моментального снимка (snapshot) текущего содержимого списка объектов Observer. Это значит, что объекту Observer, удаленному из списка в период выполнения метода notifyObservers, все еще будет послано уведомление об изменении, касающемся объекта Observable. И наоборот, если в момент осуществления   операции   notifyObservers   список   пополняется   новым   объектом Observer,  тот уведомления не получит.  Если объект Observable допускает единовременный вызов методов, генерирующих уведомления, вполне возможно, что и методы update каждого из объектов Observer также будут вызываться на конкурентной основе. Следовательно, объекты Observer обязаны использовать соответствующий механизм синхронизации внутри кода update.

  В реализациях методов notifyObservers, предлагаемых по умолчанию, предусмотрено, что вызов update осуществляется тем же потоком вычислений, которым был активизирован метод notifyObservers как таковой. Порядок рассылки уведомлений объектам Observer не регламентируется. Вполне возможно предусмотреть в классе, производном от Observable, особую модель многопоточности и/или задать строгий порядок отправки уведомлений объектам Observer.

  Рассмотрим пример, который иллюстрирует один из возможных способов организации мониторинга пользователей системы на основе протокола .   Вначале   определим   класс   Users,   производный   от

Observable.

import java.util.*;

 

public class Users extends Observable {

private Map loggedln = new HashMap();

 public void login(String name,   String password)

    throws BadUserException

{

if  (!passwordvalid(name,   password))

throw new BadUserException(name);

 

userstate state = new userState(name);

 loggedln.put(name,   state);

 setChanged();

 notifyObservers(state);

}

public void logout(userstate state) {

loggedln. remove(state. nameO) ;

setChanged() ;

notifyObservers(state);

}

//   …

}

Объект Users сохраняет коллекцию соответствий (map), которая содержит инфоР" мацию о пользователях, подключившихся к системе, и поддерживает объекты тип3 Userstate, отвечающие каждому подключению. Когда очередной пользователь подключается к системе либо, наоборот, отключается от нее, всем объектам Observer передается соответствующий объект Userstate. Метод notifyObservers рассылает сообщения только в том случае, если статус пользователя изменился; следовательно, необходимо вызывать метод setChanged объекта Users, поскольку иначе notifyObservers не выполнит ничего существенного.

  Вот как может выглядеть реализация метода update в расширенном классе Observer, который предусматривает возможности отслеживания сведений о пользователях системы:

 

import java.util.*;

 

public class  Eye implements Observer {

users watching;

public Eye(users users)  {

    watching = users;

    watching.addobserver(this);

}

public void update(Observable users,  Object whichstate)

{

if (users   != watching)

      throw new illegalArgumentException();

 

      userstate state =  (userstate) whichstate;

         if  (watching.loggedln(state))       // Пользователь подключился

           adduser(state) ;   // добавить в список

        else

           removeuser(state);            // Удалить из списка

}

Каждый объект Eye (глаз) "наблюдает" за определенным объектом Users. Когда пользователь подключается к системе либо отключается от нее, объект Eye получает уведомление об этом событии, поскольку в конструкторе Eye посредством вызова метода addObserver соответствующего объекта Users выполняется процедура регистрации Eye как "заинтересованного" объекта. Метод update выполняет проверку корректности параметра, а затем изменяет состояние объекта Eye в соответствии с тем, подключился ли пользователь к системе или "вышел" из нее.

  Анализ происшедшего события, выполняемый с учетом содержимого объекта Userstate, в данном случае намеренно упрощен. Вместо объекта UserState Методу update можно было бы передавать параметр другого типа, более полно описывающий природу события и объект, к которому оно относится; такой подход, возможно, позволил бы расширять набор функций программы без необходимости внесения изменений в существующий код.

Механизм, реализуемый на основе объектов типов , пред-

эзляет собой более свободный и гибкий аналог протокола wai t/notifу, приме-

Яемого в многопоточной среде (см. раздел 10.4). Модель многопоточных вычислений обеспечивает синхронизированный доступ к ресурсам и препятствует возникновению    нежелательных    эффектов,    связанных    с    конкуренцией потоков. Механизм позволяет устанавливать произвольные отношения между субъектами вычислительного процесса. В обоих случаях существуют как производители информации (объекты Observable и потоки-инициаторы методов notify), так и ее получатели (соответственно объекты Observer и потоки вызывающие методы wai t), но каждый из них обслуживает различные потребности Модель wai t/noti fy следует применять при проектировании процессов, основанных на потоках, а механизм — в случаях, когда требуется решение более общего характера.

Источник: Арнолд, Кен, Гослинг, Джеймс, Холмс, Дэвид. Язык программирования Java. 3-е изд .. : Пер. с англ. – М. : Издательский дом «Вильяме», 2001. – 624 с. : ил. – Парал. тит. англ.

По теме:

  • Комментарии