Observable Decoration¶
The simplest and at the same time the most pythonic variant of an
Observer
decoration is to decorate only the observed entities as an
Observable
.
Sole Observable
decoration becomes possible because all observer pattern
functionalities are concentrated in the Observable.BaseClass =
BaseObservable
of the observable decorator, while the Observer.BaseClass =
BaseObserver
of the observer decorator remains empty here. If necessary,
it is possible to inherit from both BaseClasses to modify their functionalities.
from decoratory.observer import Observable
from decoratory.basic import F
def person(say: str = "Hello?"):
print(f"{person.__name__} says '{say}'")
@Observable(observers=F(person, 'Hey, dog!'))
def dog(act: str = "Woof!"):
print(f"{dog.__name__} acts '{act}'")
# Case 1: Observable decoration
# ---> Person as an observer to observable dog
person() # person says 'Hello?' (person acting)
dog() # dog acts 'Woof!' (dog acting)
# person says 'Hey, dog!'(observer to dog)
Obviously, the addressed observer, the person, must be declared before
the observed dog. With the simpler decoration
@Observable(observers=person)
the person would always respond with their
default action and say 'Hello?'
. The usage of F
enables the transfer
of individual parameters to the observer.
Due to hierarchies in stacked observer patterns, a more detailed management of observed vs. observing objects may be necessary.
def person(say: str = "Hello?"):
print(f"{person.__name__} says '{say}'")
@Observable(observers=F(person, 'Hey, cat!'))
def cat(act: str = "Meow!"):
print(f"{cat.__name__} acts '{act}'")
@Observable(observers=[F(cat, 'Roar!'), F(person, 'Hey, dog!')])
def dog(act: str = "Woof!"):
print(f"{dog.__name__} acts '{act}'")
# Case 2: Stacked observable decoration
# ---> Cat observes dog, person observes cat and dog
person() # person says 'Hello?' (person acting)
cat() # cat acts 'Meow!' (cat acting)
# person says 'Hey, cat!'(observer to cat)
dog() # dog acts 'Woof!' (dog acting)
# cat acts 'Roar!' (observer to dog)
# person says 'Hey, cat!'(observer to cat)
# person says 'Hey, dog!'(observer to dog)
Person is an observer, but not an observable, so the call to person()
reflects only person’s own activity.
Cat is an observable that is observed by person and therefore the activity
cat()
triggers a follow-up activity by person.
Calling dog()
results in three activities at the observers, because
dog()
is observed by the observed cat, which informs the person about
its own activity.
The order of reactions is determined by the order in the list in which the cat observes the dog prior to the person. If this order is reversed, the order of the observers’ reactions also changes.
@Observable(observers=[F(person, 'Hey, dog!'), F(cat, 'Roar!')])
def dog(act: str = "Woof!"):
print(f"{dog.__name__} acts '{act}'")
# Case 3: Stacked observable decoration in reversed order
# ---> Cat observes dog, person observes dog and cat
dog() # dog acts 'Woof!' (dog acting)
# person says 'Hey, dog!'(observer to dog)
# cat acts 'Roar!' (observer to dog)
# person says 'Hey, cat!'(observer to cat)
Again, calling dog()
results in three activities at the observers, but here
person reacts first as an observer to dog and later again as an observer to
cat.
If this behavior is not desired, dog()
can instead be observered by the
original cat using the cat.substitute.callee
, i.e.
@Observable(observers=[F(cat.substitute.callee, 'Roar!'),
F(person, 'Hey, dog!')])
def dog(act: str = "Woof!"):
print(f"{dog.__name__} acts '{act}'")
# Case 4: Stacked observable decoration observing original entities
# ---> Original cat observes dog, person observes dog and cat
dog() # dog acts 'Woof!' (dog acting)
# cat acts 'Roar!' (observer to dog)
# person says 'Hey, dog!'(observer to dog)
In this case, cat acts before person because of the order of the observer list
and because the original cat observes dog the person’s Hey, cat!
statement
is missing.
© Copyright 2020-, Martin Abel, eVation. All Rights Reserved. |