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