There is often a need to develop systems that listen on some kind of event. If you have ever encountered even a bit of Javascript, you saw those onChange, onClick, onKeyUp, and so on. We have a concept of a subject that contains a certain state. Once that state changes, all of the listeners get notified. Very similar structure can be seen in such systems as news publications. We would get notification if we get a fresh release of a newspaper. In this scenario, our publisher would be the subject, and it would have a state. If we get a fresh newspaper, the onNewRelease event gets activated, and then a listener, meaning, subscriber, gets notified of that.
From this we can obviously conclude that there should be at least two different objects: Subscriber and Publisher. What’s important in our scenario is to enable objects to subscribe easily, and as easily unsubscribe from notifications. To do that we must ensure that all of the subscribes abide by same rules of subscription: particular set of methods. We can do that with the use of interface. On top of that, publisher must be able to keep track of all of the subscribers they have, so they know to whom send notifications. We can do that by making a list of all of those subscribers inside the Publisher class. For all of these problems Observer design pattern has a solution.
Observer Pattern:
defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically.
It exactly fits our case and perfectly solves some of the problems due to following reasons:
- We have a one-to-many (publisher-to-subscribers) relationship, and in good traditions of OOP we ought to make them as loosely coupled as possible
- It contains a mechanism to update all of the dependents on state change of the object (publisher), and that it does it automatically
Loose coupling within this pattern means that observers have ho idea what’s the underlying logic and structure of the observable object is. They only get notified if it does change or not. On top of that we get dynamic assignment: ability to add or remove subscribers from the list at the runtime. Additionally, we should not rely on the order of evaluation, i.e. which observers get updated first and last, because that would again expose extra knowledge to us and make it more tightly coupled.
There are two models that can differ the behavior of the observer pattern. There is Push Model and Pull Model. In Push model the observer is notified of change, and they must figure out what the change it, meaning the observer will need to call a method to get the latest state. Whereas in Pull Model, observable sends the state to all of its observers. In the case of our problem: Publisher and Subscribers – we could really go either way of implementation. We can say that we only send out emails to our subscribers. Or we can say that once you are out subscriber you will be getting the newspaper every time there is a new release. The main difference between the two is how information is transmitted.
# source: https://en.wikipedia.org/wiki/Observer_pattern
class Observable:
def __init__(self):
self.__observers = []
def register_observer(self, observer):
self.__observers.append(observer)
def notify_observers(self, *args, **kwargs):
for observer in self.__observers:
observer.notify(self, *args, **kwargs)
class Observer:
def __init__(self, observable):
observable.register_observer(self)
def notify(self, observable, *args, **kwargs):
print('Got', args, kwargs, 'From', observable)
subject = Observable()
observer = Observer(subject)
subject.notify_observers('test')
Observer Pattern is very useful design technique and can be seen used in variety of existing languages and software. Taking example of Javascript, it is also often found as a part of MVC pattern. Java has its own libraries dedicated to those classes: java.util.Observer and java.util.Observable. In any system where there is a clear one-to-many relationship and the need for notification mechanism, Observer Pattern can come across as one of the most obvious solutions.


2 thoughts on “Observer Pattern”