OcempGUI provides a minimalistic observer pattern implementation
in the ocempgui.events
module, which
enables objects to track changes ('observe') from others. Two
classes, the Subject
and
IObserver
, are used for this.
An object, which should expose changes is usually called a subject
to which other objects, the observers, subscribe for notification
about those changes. To create a subject, the class just needs to
inherit from the Subject
class, which
provides a minimum set of methods and attributes to become
observable.
class MyObject (Subject): def __init__ (self): Subject.__init__ (self, "UniqueSubjectName") ...
Subject
receives a
string argument, the name, which identifies the object instance
for possible observers.
The object now features all attributes and methods to register
observers and to notify them about state changes. State changes
however have to be emitted manually, so that the object should
invoke its notify()
method, whenever this
is necessary.
class MyObject (Subject): def __init__ (self): Subject.__init__ (self, "UniqueSubjectName") self._value = None def set_value (self, value): # Preserve old value. oldval = self._value # Set new value. self._value = value # Notify observers self.notify ('value', old, value) ...
set_value()
is invoked now, any
registered observer will be notified about
The object, that changed its state (UniqueSubjectName).
The name of the object part that changed (here the attribute value).
The old and new value of the object part that changed.
An object that shall act as an observer should inherit from the
IObserver
class and implement its
update()
method, which will receive the
state change notification from the Subject
.
The signature of the method looks like the following:
class ObserverObject (IObserver): ... def update (self, subject, prop, oldval, newval): ...
Your classes do not need to explicitly inherit from
IObserver
, but have to implement the
update()
method with its correct
signature.
The subject
argument is the unique name of
the Subject
that just
changed. prop
identifies the detail that
changed and oldval
and
newval
contain the old and new value of the
detail.
The following example is a complete example based on the
excerpts from above. You can find it as python script under
examples/observer.py
# Subject/Observer usage example. from ocempgui.events import Subject, IObserver # The subject that should notify observers about state changes. class MyObject (Subject): def __init__ (self): Subject.__init__ (self, "MyObject") self._x = "Simple Attribute" self._y = 1234567890 self._z = None def get_x (self): return self._x def set_x (self, value): # Preserve old value. old = self._x self._x = value # Notify about change. self.notify ("x", old, value) def get_y (self): return self._y def set_y (self, value): # Preserve old value. old = self._y self._y = value # Notify about change. self.notify ("y", old, value) def get_z (self): return self._z def set_z (self, value): # Preserve old value. old = self._z self._z = value # Notify about change. self.notify ("z", old, value) x = property (get_x, set_x) y = property (get_y, set_y) z = property (get_z, set_z) class OwnObserver (IObserver): def __init__ (self): pass def update (self, subject, prop, oldval, newval): if subject == "MyObject": # A MyObject instance, check details. if prop == "x": # Its x value changed. print "The x value of a MyObject instance changed from " \ "%s to %s" % (str (oldval), str (newval)) elif prop == "y": # Its y value changed. print "The y value of a MyObject instance changed from " \ "%s to %s" % (str (oldval), str (newval)) else: # Another value changed. print "The %s value of a MyObject instance changed from" \ "%s to %s" % (str (prop), str (oldval), str (newval)) class AnotherObserver (IObserver): def __init__ (self): pass def update (self, subject, prop, oldval, newval): print "Detail %s of %s changed from %s to %s" % (str (prop), subject, str (oldval), str (newval)) subject = MyObject () # Add tow observers doing observer1 = OwnObserver () observer2 = AnotherObserver () subject.add (observer1, observer2) subject.x = "FooBarBaz" subject.y = subject.x * 3 subject.z = 100
Example 11. Observer example