Skip to content

Latest commit

 

History

History
133 lines (91 loc) · 5.3 KB

File metadata and controls

133 lines (91 loc) · 5.3 KB

Model-View Architectures > 3_Model_View > Observer_patterns

Observer patterns :

This part references the different observer mechanisms used by the application.


An Observer Pattern is a behavioral pattern commonly used in software engineering. It defines a one-to-many dependency between objects, so that when one object (the subject) changes its state, all dependent objects (the observers) are automatically notified and updated.

This facilitates synchronization between objects without them needing to know each other.
Everything is registered by the model they use without the need to know who is using it.

All they need to do is be on the list of observers to be notified.


Object Observer

The simplest one is the Object Observer which simply sets an observer to an observable object.

The Observable object has no knowledge of the Observer objects but has a list of "observers" to notify.

This mechanism is possible by calling the notify method of each object registered in this list.
This therefore means that a notify method must be defined in each observer whatever its type.

To show how to implement this step, an ObserverObject class has been defined as an example with a notify method and an automatic call to the add_observer method of the observable object during its initialization.

class ObserverObject:

    def __init__(self, observable):
        observable.add_observer(self.notify)

    def notify(self, observable, *args, **kwargs):
        print(self, "Got", args, kwargs, "From", observable)

The Observable class has only 3 little methods :

  • add_observer : for registering an observer into the 'observers' list when the observation is needed.
  • remove_observer : for removing an observer from the 'observers' list when the observation is not more needed.
  • notify_observers : for calling the notify methods of each object registered in the 'observers' list.
class Observable:

    def __init__(self):
        self._observers = []

    def add_observer(self, observer : callable):
        if observer not in self._observers:
            self._observers.append(observer)

    def remove_observer(self, observer : callable):
        if observer in self._observers:
            self._observers.remove(observer)

    def notify_observers(self, *args, **kwargs):
        for observer in self._observers:
            observer(*args, **kwargs)

Note: It might have been interesting to create an abstract class of ObserverObject to make the user derived from it. But since the models are already generic and maybe not so easy to understand, I decided not to overload the code and to keep it simple by integrating the mechanism directly.

More about : Observer_pattern on Wikipedia


File Observer Handler

Here is the same kind of notifier except that this one is specially designed to observe files out of the application scope.

It uses the Observer and FileSystemEventHandler mechanisms of the watchdog Python library for being notified by the monitoring file system events.

The application needs to create a FileObserverHandler object with in parameters :

  • the absolute path of the file (shared_file) to observe
  • and the reference of the notify function (notify_on_modified) to call when a modification appears on this file.
if __name__ == "__main__":

    shared_file = os.path.abspath("shared_file.txt")
    
    def notify_on_modified(event):
        print(f"notify_on_modified : {event}")
    
    file_observer_handler = FileObserverHandler(shared_file, notify_on_modified)

then it needs to create an Observer object to register this file_observer_handler into the list of 'observers to notify'.

    observer = Observer()
    observer.schedule(file_observer_handler, path=os.path.dirname(shared_file), recursive=False)
    observer.start()

FileObserverHandler inherits from FileSystemEventHandler and overrides the on_modified method, but it may also override on_created, on_deleted, on_moved, on_opened, on_closed, or on_any_event to be notified for these other kind of events.

class FileObserverHandler(FileSystemEventHandler):

    def __init__(self, shared_file_abspath, notify_function):
        self.shared_file_abspath = shared_file_abspath
        self.notify_function = notify_function

    def on_modified(self, event):
        if event.is_directory:
            return
        if event.src_path == self.shared_file_abspath:
            self.notify_function(event)

More about : FileSystemEventHandler on https://pythonhosted.org/


Model-View Architectures > 3_Model_View > Observer_patterns