December,
2002
Vladimir Trukhin
Senior Software Engineer
JSC "Votkinsk Hydroelectric Power Plant"
Fax: +7 (34241) 63297
E-mail: vlt@votges.ru
This article was
first published in the March, 2002 issue of FoxTalk
Manager
of the Objects Linked by Common Data
The objects know all
about themselves, but they know little about their neighbors
in an application. However, as Vladimir Trukhin shows us
here, each of them can affect other objects. The application
needs something to notify the objects about a change of
environment—the Manager of the Objects.
You can create a
form and connect it with data. What could be easier? It's very
easy, especially in Visual FoxPro. Furthermore, you can create
many forms, good and different. Each of them, as a rule,
displays the data of some table or, more often, several
tables.
Is it possible
that some forms display the same data? Certainly—this
frequently the case. Besides, the forms can have private data
sessions. If you load some such forms and make changes in one
of them, you won't see the change in other forms until you've
made them via some mouse or keyboard manipulations. The
situation becomes even worse if you create and start classes
distinct from forms. They can be invisible to you, and you
can't get to them by mouse. What's the solution?
Someone
should take command Yes,
"someone" should do it. In this case, there's some
ambiguity, which can misinform you and lead to incorrect
results. I've named this "someone" the Manager of
Objects. It can exist during the entire operating time of the
application, while there will be objects linked by common
data. And so, I create an instance of the Manager, in this
case as a public variable to make the example easier to
follow:
PUBLIC goDLOM && where DLOM is Data Linked Objects Manager
goDLOM=CREATEOBJECT('DataLinkedObjectManager')
Now it's ready to command, but
does the Manager know what objects work with the same data
set? No, it doesn't. The Manager won't know anything about
these objects if they don't declare anything about themselves.
Each object, when it's created, should be registered in the
Manager. It's most convenient to have this happen in the Init
method of the created object:
PROCEDURE Init
goDLOM.AddClient(THIS)
ENDPROC
When the Manager knows all the
participants of the game, it can serve as the referee. How can
it know what's taken place with one object or another? The
Manager knows nothing about objects, and it can't determine
what happens with them. An object can know only about itself.
In changing the data, the
object should inform the Manager about it, and the Manager, in
turn, must inform all other objects of this event, excepting
the hero of the occasion. Usually, for this purpose I use the
object's SomeControlLostFocus method and the object's
DataSetIsChanged property, which confirms the real change of a
data set.
Who
will refresh the data? It's high time to ask,
"Can the Manager update the data of objects?" Each
participant of the game should have its own method, which is
named RefreshData, to update its data. In this method of an
object, the logic of reception of the fresh data will be
latent. Upon receiving the notification from an active object,
the Manager will just need to call this method for all
objects.
What
happens if someone is too tired to play? The objects don't
exist eternally, and they're sometimes unloaded from memory.
The Manager should be notified about such a sad fact. The
object must do so itself, before it has died. The most
suitable place for this to occur is in the Unload method of
the object:
How
many nuts in a pocket? If someone wants to
find out the number of participants in the game, it can ask
the Manager, using the NumberOfClients property.
Definition
of a Manager class Now that all of the
conditions have been determined, it's time to generate the
list of properties and methods of a Manager class (see Table
1).
Table 1.
Properties and methods of the Manager class.
Name of member
Type
Description
AddClient
Method
Adds a new object to
client list.
NumberOfClients
Property
Gives the number of
registered clients.
RemoveClient
Method
Removes the specified
object from the client list.
UpdateAllClients
Method
Updates the data sets
of all registered clients.
In my applications I use the
following definition of the class:
*-- Class: DataLinkedObjectManager
*-- ParentClass: Custom
*-- BaseClass: Custom
DEFINE CLASS DataLinkedObjectManager AS custom
Name='DataLinkedObjectManager'
** The list of clients to be driven by this manager
DECLARE CLIENTS(1)
** Number of registered clients
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
** Adds a new client into client list
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
** Removes a specified client from client list
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
** Updates data sets of all registered clients
PROCEDURE UpdateAllClients
LPARAMETERS loPushingObject
LOCAL loCurrentObject
IF THIS.NumberOfClients > 0
FOR EACH loCurrentObject IN THIS.Clients
IF loCurrentObject != loPushingObject
loCurrentObject.RefreshData()
ENDIF
ENDFOR
ENDIF
ENDPROC
ENDDEFINE
Conclusion Most applications
aren't limited to one data set. Therefore, for each such set
it's possible to create an instance of the Manager class.
Besides, some objects can be registered in several Managers,
if their data crosses several data sets of the application.
You can download the class
source code from file:
dlom.zip.
Size:
1KB.