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.

Pyc. 37 Sole observable decoration
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.

Pyc. 38 Stacked observable decoration
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.

Pyc. 39 Stacked observable decoration in reversed order
@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.

Pyc. 40 Stacked observable decoration observing original entities
@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.


◄ prev

up

next ►

Legal Notice

Privacy Policy

Cookie Consent

Sphinx 7.2.6 & Alabaster 0.7.12

© Copyright 2020-, Martin Abel, eVation. All Rights Reserved.