---
# System prepended metadata

title: Observer Pattern General Example
tags: [Python, CMSC23, OOP, Notes]

---

## Observer Pattern

### Problem

What if you need to inform a lot of objects about the changes to some interesting data? If you globalize the data and let your client objects poll for changes all the time, this will affect the security and safety of your interesting data. Plus, global data is something that should be avoided as much as possible. Also, forcing your objects poll for changes all the time will be inefficient if your interesting data has not changed.

![observer](https://raw.githubusercontent.com/HowDoIGitHelp/CMSC23MDNotes/master/Markdown%20Lecture%20Notes%20and%20Lab%20Exercises/copyright%20free%20drawings/Observer.png)

### Solution

The responsibility of sharing information about the changes to interesting data should not be placed in the clients of the data. You should create a notifier class that encapsulates the interesting data. This class should be responsible of notifying interested clients about changes on the data. 

To do this you need to encapsulate the interesting data (from now on lets call it the `subject`), into a `Publisher` class. An instance of this class will be responsible of notifying the observers for any change in the `subject`. Whenever there are changes to the subject, the `Publisher` instance calls `notifyObservers()` so that all interested, observers will be informed of the change. Any class that is potentially interested in the `subject` should realize an `Observer` abstraction, which in the bare minimum contains, the `update(updatedSubject)` function. Inside `Publisher`'s `notifyObservers()` method, every subscriber (an interested observer) is updated (`subscriber.update()`).

Any instance of an `Observer` should be subscribed to the change notifications using `Publisher`'s `subscribe()` function. They can also be unsubscribed using the`unsubscribe()` function.

![observer](https://raw.githubusercontent.com/HowDoIGitHelp/CMSC23MDNotes/master/Markdown%20Lecture%20Notes%20and%20Lab%20Exercises/uml/observer.png)

### General Example
```python!
from abc import ABC, abstractmethod
class Observer(ABC):
    @abstractmethod
    def update(self,subject:str):
        pass

class Publisher:
    def __init__(self,subject:str):
        self.__subject = subject # this could be any object that is interesting to observers
        self.__subscribers = []

    def subject(self) -> str:
        return self.__subject

    def manipulateSubject(self, someString:str):
        self.__subject = someString
        self.notifyObservers()

    def subscribe(self, observer:Observer):
        self.__subscribers.append(observer)
        observer.update(self.__subject)

    def unsubscribe(self, observer:Observer):
        if observer in self.__subscribers:
            self.__subscribers.remove(observer)

    def notifyObservers(self):
        for observer in self.__subscribers:
            observer.update(self.__subject)

class RealObserver1(Observer):
    def __init__(self,name:str):
        self.__name = name
        self.__subject = None

    def update(self,subject:str): # everything that the observers should be notified of should be passed here
        self.__subject = subject
        print("Subject has been updated to " + self.__subject)
        print("Performing observer1 behavior in response to change")

class RealObserver2(Observer):
    def __init__(self,name:str):
        self.__name = name
        self.__subject = None

    def update(self,subject:str):
        self.__subject = subject
        print("Subject has been updated to " + self.__subject)
        print("Performing observer2 behavior in response to change")

p = Publisher("initial value")
o1 = RealObserver1("o1")
o2 = RealObserver2("o2")

p.subscribe(o1)
p.subscribe(o2)
print()

p.manipulateSubject("new value")
print()

p.unsubscribe(o1)

p.manipulateSubject("newer value")

p.unsubscribe(o2)

print()
p.manipulateSubject("newest value")
```

> Whenever an observer has updated, the publisher needs to pass all the necessary details in the notification. This is generally done by passing the updated subject in the `update(updatedSubject)` method.
>
> In some cases, the observer needs to keep a copy of the subject as an attribute. Make sure to change the value of this  attribute during updates.
>
> Make sure that changes to the subject are only done using the `Publisher` class (`manipulateSubject()`). If you change the subject without using `Publisher`'s methods, your subscribers won't be notified.

### Why this is elegant

- **Open/Closed Principle** - You can add new `Observer` realizations seamlessly every time there are new objects that are interested in the subject.
- A observer can be subscribed/unsubscribed during runtime

### How to implement it

1. Create an `Observer` abstraction that represents all classes that can potentially observe changes to the `Publisher`. `Observer` will contain the abstract method `update()`.
2. All classes that want to be notified about changes to the `subject` should realize `Observer`.
3. `Publisher` will either own/use an instance of the `subject` of interest. It will also use an attribute which is stores the list of `Observers` that are interested in the subject. To attach or detach `Observer`s, `Publisher` contains the methods `subscribe()` and `unsubscribe()`.
4. Every time `subject` is manipulated, it should be done through `Publisher` , because `Publisher` needs to notify all `Observers` in its observer list attribute after every manipulation. This notification is done through `notifyObservers()` after the end of every subject manipulation.
5. Inside the `Publisher`s `notifyObservers` method, every `Observer` in its list of observers invoke their `update()` method.

