-
Notifications
You must be signed in to change notification settings - Fork 1
The Dependency Mechanism 3
Dr. Nicola Mingotti edited this page Jan 23, 2022
·
13 revisions
- In Cuis the dependency is handled with the Observer pattern
- In the observer pattern an object called subject maintains a list of observers. The subject notifies its observers when it changes.
- In Cuis the Parent-Dependent pattern is implemented with the Subject-Observer this way
Parent-Dependent | Subject-Observer | |
connection making. objB wants to be informed of changes in objA. | objA addDependent: objB |
objA when: #changed send: #update to: objB |
objA tells the objects who are watching it that it changed state. | objA changed: #param |
objA triggerEvent: #changed with: #param |
when objA state changes the message update is sent to objB with a parameter. |
objB update: #param |
objB update: #param |
we want objB to stop watching objA | objA removeDependent: objB |
objA removeActionWithReceiver: objB forEvent: #changed |
- Observe that the parameter
#changed
is used explicitly in Cuis to build Parent-Dependent pattern, but that is actually a free parameter in the Observer model. - In Cuis6 Model is substituted by ActiveModel, if you look into the implementation of the Parent-Dependent pattern you will see that dependencies between objects go by default stored in class variable ActionMaps of ActiveModel . This instead of using class variable DependentsFields of class Object, as done in the classic implementation, for example in VisualWorks and Squeak.
-
Exercise. Use
ActiveModel actionMaps
to explore the ActionMaps class variable content. - Mirroring our previous example in the Parent-Dependent model, we impolement of two simple classes (in the Subject-Observer model) MyActiveNumber and MyObserverNumber for objects objA and objB, where objB is observer for objA. We want to keep the dependency mechanism localized so MyActiveNumber will be subclass of ActiveModel (instead of Object). When objA changes we want objB to receive the message
update
, we don't want to pass any parameter, objB will ask what it need to objA. You can get the fileout here: MyActiveNumber.st and MyObserverNumber.st .
ActiveModel subclass: #MyActiveNumber
instanceVariableNames: 'value'
MyActiveNumber >> initialize
value := 0.
^ self
MyActiveNumber >> value
^ value
MyActiveNumber >> value: aNumber
value := aNumber
self triggerEvent: #iChanged
Object subclass: #MyObserverNumber
instanceVariableNames: 'value model'
MyObserverNumber class >> newWithModel: anObject
^ super new initializeWithModel: anObject
MyObserverNumber >> initializeWithModel: anObject
value := 0.
model := anObject .
model when: #iChanged send: #update to: self .
^ self
MyObserverNumber update
|vPar vMe |
vPar := model value.
vMe := vPar * 2.
value := vMe.
Transcript show: ('my MODEL value is:{1} and mine is value:{2}' format: {vPar. vMe} ).
MyObserverNumber value
^ value
- Then try everything works with a little interaction from the Workspace
objA := MyActiveNumber new.
objB := MyObserverNumber newWithModel: objA.
objA value . "=> 0"
objB value. "=> 0"
objA value: 10.
objB value. "=> 20"
- Exercise. explore objA and convince your self it contains the map toward object objB.