English Version - www.geocities.com/vhpcg
VHP Computing Group
ТехнологииПродукцияМатериалыСпециалистыПартнёрыЗапись в Гостевую КнигуПросмотр Гостевой Книги

Декабрь, 2000
Владимир Трухин
ведущий инженер-программист
ОАО "Воткинская ГЭС"
Fax: +7 (34241) 63297
E-mail:
vlt@gesvt.permenergo.ru
vlt@votges.ru

Эта статья была опубликована в журнале FoxTalk (March 2002) и FoxTalk Русское издание (Июнь 2002). При любом повторном издании необходима ссылка на эти источники.

Диспетчер объектов, связанных общими данными

О себе объекты знают всё,  но они не знают практически ничего о своих ближайших соседях по приложению. Однако, каждый из них может влиять на другие объекты. Приложению нужен кто-то, кто стал бы информировать объекты об изменениях, происходящих в программной среде. Им может стать Диспетчер объектов.

Вы можете создать форму и связать её с данными. Что может быть проще? Особенно в Visual FoxPro. Вы можете создать много форм, хороших и разных. Каждая из них, как правило, отображает данные какой-либо таблицы или, чаще всего, нескольких таблиц. А может случиться так, что некоторые формы отображают одни и те же данные?

Конечно, такая возможность вполне допустима и очень часто используется. Кроме того, формы могут иметь частные сеансы данных. Загрузив несколько таких форм и сделав изменения в одной из них, вы вряд ли увидите это изменение в остальных формах до тех пор, пока не произведёте с ними некоторые манипуляции мышью или клавиатурой. Положение становится ещё хуже, если вы создаёте и запускаете классы отличные от форм. Они могут быть невидимы для пользователя. Их нельзя потрогать мышкой. Что предпринять?

Кто-то должен взять командование на себя.

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

PUBLIC goDLOM && где DLOM - Диспетчер объектов (Data Linked Objects Manager)goDLOM=CREATEOBJECT(‘DataLinkedObjectManager’)

Сейчас он готов командовать объектами, но возникает вопрос: «Знает ли он, какие объекты работают с одним набором данных?». Ответ – нет, он не знает. Диспетчер не будет знать ничего об этих объектах, пока они сами не заявят о себе. Каждый объект, когда он уже создан, должен зарегистрироваться в Диспетчере. Удобнее всего сделать это в методе Init созданного объекта:

PROCEDURE Init
  goDLOM.AddClient(THIS)
ENDPROC

Поскольку диспетчер знает всех участников игры, он мог бы выступить в качестве арбитра. Знает ли он, что произошло с тем или иным объектом? Ответ всё тот же - нет. О состоянии объекта может знать только сам объект и никто кроме него.

Изменив свои данные, объект должен сообщить об этом Диспетчеру, а тот, в свою очередь, сообщить всем остальным объектам, исключая виновника произошедшего события. Обычно я использую для этого метод объекта SomeControleLostFocus и свойство объекта DataSetIsChanged, которое подтверждает действительное изменение набора данных.

PROCEDURE SomeControleLostFocus
IF THIS. DataSetIsChanged
  * … updating code …
  goDLOM.UpdateAllClients(THIS)

ENDIF

«Свершилось чудо. Друг спас жизнь друга…»

Свершилось ли чудо? Боюсь, что нет. Для того чтобы это произошло, каждый участник игры должен иметь собственный метод, названный RefreshData. Именно в этом методе объекта будет скрыта логика получения свежих данных. Именно этот метод будет вызывать Диспетчер для всех объектов, получив извещение от активного объекта.

Если кто-то устал играть.

Объекты существуют не вечно, случается, что они иногда выгружаются из памяти. Диспетчер должен быть поставлен в известность о таком печальном факте. Сделать это придётся самому объекту, пока он ещё не умер окончательно. Самое подходящее место для этого – метод Unload объекта.

PROCEDURE Unload
  goDLOM.RemoveClient(THIS)

ENDPROC

Сколько орехов в мешке?

Если кто-то захочет узнать число участников игры, он сможет спросить об этом у Диспетчера, используя свойство NumberOfClients.

Определение класса Диспетчера

Все условия определены, пришло время сформировать список свойств и методов Диспетчера.

      Таблица свойств и методов класса

Name of member

Type

Description

  AddClient

  Method

 Добавляет новый объект в список клиентов

NumberOfClients

Property

Количество зарегистрированных клиентов

RemoveClient

Method

Удаляет указанный объект из списка клиентов

UpdateAllClients

Method

Обновляет наборы данных всех зарегистрированных клиентов

 В своих приложениях я использую следующее определение класса Диспетчера (файл для загрузки DLOM.ZIP):

*-- Class:      DataLinkedObjectManager
*-- ParentClass:  Custom
*-- BaseClass:      Custom

DEFINE CLASS DataLinkedObjectManager AS custom

  Name='DataLinkedObjectManager'

  ** Список клиентов, управляемых Диспетчером

 DECLARE CLIENTS(1)

 ** Количество зарегистрированных клиентов
  NumberOfClients=0

PROCEDURE NumberOfClients_access
       LOCAL lnNumberOfClients
       IF ALEN(THIS.Clients)=1 AND ISNULL(THIS.Clients(1))
         lnNumberOfClients=0
       ELSE
         lnNumberOfClients=ALEN(THIS.Clients)
       ENDIF
       RETURN lnNumberOfClients
ENDPROC

PROCEDURE NumberOfClients_assign
    LPARAMETERS vNewVal
    RETURN
ENDPROC

PROCEDURE Init
    THIS.Clients(1)=NULL
ENDPROC

PROCEDURE Release
    RELEASE THIS
  ENDPROC

** Добавляет нового клиента в список клиентов
  PROCEDURE AddClient
    LPARAMETERS loReference
       IF THIS.NumberOfClients=0
         THIS.Clients(1)=loReference
       ELSE
         DIMENSION THIS.Clients(THIS.NumberOfClients+1)
         THIS.Clients(THIS.NumberOfClients)=loReference
       ENDIF
ENDPROC

** Удаляет указанного клиента из списка клиентов
  PROCEDURE RemoveClient
    LPARAMETERS loReference
       LOCAL lnElement, llSuccess, lnIndex
    lnElement=0
       FOR lnIndex=1 to THIS.NumberOfClients
         IF THIS.Clients(lnIndex)=loReference
                lnElement=lnIndex
                EXIT
         ENDIF
       ENDFOR
       IF lnElement!=0
         IF THIS.NumberOfClients=1
                THIS.Clients(1)=NULL
         ELSE
                ADEL(THIS.Clients,lnElement)
                DIMENSION THIS.Clients(THIS.NumberOfClients-1)
         ENDIF
         llSuccess=.T.
       ELSE
         llSuccess=.F.
       ENDIF
       RETURN llSuccess
ENDPROC    

** Обновляет наборы данных всех зарегистрированных клиентов      
  PROCEDURE UpdateAllClients
    LPARAMETERS loPushingObject
       LOCAL loCurrentObject
       IF THIS.NumberOfClients > 0
         FOR EACH loCurrentObject IN THIS.Clients
                IF loCurrentObject != loPushingObject
                  loCurrentObject.RefreshData()
                ENDIF
         ENDFOR
       ENDIF
    loPushingObject.Activate()
ENDPROC

ENDDEFINE

Заключение

Большинство приложений не ограничивается одним набором данных, поэтому для каждого такого набора можно создать свой экземпляр класса диспетчера. Кроме того, некоторые объекты могут регистрироваться в нескольких диспетчерах, если их данные – это пересечение нескольких наборов данных приложения.



Главная страница | Технологии | Продукция | Материалы | Специалисты | Партнёры
Запись в Гостевую Книгу | Просмотр Гостевой Книги

 
1