The Order of the Stick (doesn't allow hot linking :( ).
I know, no great new findings here, but I thought it'd be nice to share to those few out there who may not actually have seen either of these strips before.
class Observable( object ):attach_observer and detach_observer maintain the list of Observers that are interested in this object. After any change in state, notify_all should be called. If this state change is part of a larger transaction, the combination set_dirty and notify_check should be called.
def __init__( self, *args, **kwargs ):
super( Observable, self ).__init__( *args, **kwargs )
self.__dirty = False
self.__observers = weakref.WeakKeyDictionary( )
def attach_observer( self, obs ):
if obs not in self.__observers:
self.__observers[obs] = 1
return self
def detach_observer( self, obs ):
if obs in self.__observers:
del self.__observers[obs]
return self
def set_dirty( self, d ):
self.__dirty = d
return self.__dirty
def is_dirty( self ):
return self.__dirty
def notify_all( self ):
for observer in self.__observers.keys( ):
observer.observer_update( self )
def notify_check( self ):
if self.is_dirty( ):
self.notify_all( )
self.set_dirty( False )
The Observer object is very easy to implement. Really, only it needs observer_udpate defined since that method is called by Observable during notify_all. The observed object passes itself as the argument to observable_update so that the observer knows which of the objects it currently is observing has been updated.
class Observer( object ):
def __init__(self, *args, **kwargs ):
pass
def observer_update( self, object ):
pass
class EventObserver( object ):
def __init__( self, *args, **kwargs ):
super( EventObserver, self ).__init__( *args, **kwargs )
@channel_processor
def event_transieve( self, *args, **kwargs ):
evt = kwargs.get( 'data', None )
self.process_event( evt )
def process_event( self, event ):
pass
def event_notify( self, event ):
self.event_transieve( event )
Now, we can safely ignore the attach_event_observer and methods -- they only exist to implement the Observer pattern. The only method we really care about at the moment is dispatcher.
class EventObservable( object ):
def __init__( self, *args, **kwargs ):
super( EventObservable, self ).__init__( *args, **kwargs )
self.__event_observers = weakref.WeakKeyDictionary( )
self.__events = [ ]
def attach_event_observer( self, obs, level=1 ):
if obs not in self.__event_observers:
self.__event_observers[obs] = level
return self
def detach_event_observer( self, obs ):
if obs in self.__event_observers:
del self.__event_observers[obs]
return self
@channel_processor
def dispatcher( self, *args, **kwargs ):
data = kwargs.get( 'data', None )
wlist = []
for key in self.__event_observers.keys( ):
val = self.__event_observers[key]
seok = SortableEventObserverKey( key, val )
heapq.heappush( wlist, seok )
while len( wlist ):
obs = heapq.heappop( wlist )
obs( evt )
def dispatch_event( self, event ):
self.dispatcher( event )
return event
class SortableEventObserverKey( object ):
def __init__( self, kval, weight, *args, **kwargs ):
super( SortableEventObserverKey, self ).__init__( *args, **kwargs )
self.__value = kval
self.__weight = weight
def __cmp__( self, other ):
return cmp( self.__weight, other.__weight )
def __call__( self, event ):
return self.__value.event_notify( event )
def __repr__( self ):
return "%s, %s" % ( self.__value, self.__weight )
class EventParticipant( EventObservable, EventObserver ):
def __init__( self, *args, **kwargs ):
super( EventParticipant, self ).__init__( *args, **kwargs )
event_manager = kwargs.get( "event_manager", "events" )
self.event_manager = pytypes.get_event_manager( event_manager )
def generate_event( self, event_type, *data, **kwargs ):
evt = self.event_manager.create_event( self, event_type, *data, **kwargs )
return self.dispatch_event( evt )