In my last article, I discussed the Singleton pattern, which falls under the Creational Design Pattern. The Observer pattern is classified under the Behavioral design pattern by GoF. By defining clear relationships and interactions between objects, behavioral design patterns help make your code more flexible, maintainable, and easier to understand.
Behavioral design patterns are a subset of design patterns in software engineering that deal with the communication and interaction between objects and classes. These patterns focus on how objects collaborate and delegate responsibilities to achieve specific behaviors and functionalities in a software system.
What is Observer pattern?
The Observer Pattern is a behavioral design pattern that establishes a relationship where one object (known as the subject or observable) informs multiple dependent objects (observers) about any changes in its state. Essentially, it provides a way to broadcast change notifications from a single object (the subject) to multiple objects (observers) that rely on it. Due to this its also known as Publisher - Subscriber Pattern
The Observer pattern is useful when you are interested in the state of an object and want to get notified whenever there is any change. Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
Here's how the Observer Pattern works:
1. Subject (Observable)
This is the object that is being observed. It maintains a list of observers and provides methods for attaching, detaching, and notifying observers. When the subject's state changes, it notifies all its observers.
2. Observer
Observer objects are interested in the state changes of the subject. They register with the subject to receive updates. When the subject's state changes, it calls the update method on each registered observer.
Let's try to understand Observer design patterns with the help of a simple Python example. Consider you have got a YouTube channel to which 100s of users have subscribed. As and when you create new content and upload it to your YouTube channel, you would like to send notifications to all the users who have subscribed to your channel.
To implement this scenario we need to create a class to denote YouTube channel (Subject) and a few methods like subscribe() to subscribe(s) to a particular YouTube Channel and notify() to notify the subscribed event.
class YoutubeChannel:
def __init__(self, name):
self.name = name
self.subscribers = []
def subscribe(self, sub):
self.subscribers.append(sub)
def notify(self, event): # send notification to subscriber
for sub in self.subscribers:
sub.sendNotification(self.name, event)
Now to implement subscriber (observer) to a particular event (subject), we can either use an abstract class or interface.
# Refer https://docs.python.org/3/library/abc.html for more information
from abc import ABC, abstractmethod
class YoutubeSubscriber(ABC):
""" Abstract method which defines the interface.
Concrete class needs to implement abstract method.
"""
@abstractmethod
def sendNotification(self,event):
pass # implentation needed in concrete class
class YoutubeUser(YoutubeSubscriber):
def __init__(self, name):
self.name = name
def sendNotification(self,channel, event):
print(f"User {self.name} recived notification from {channel} : {event}")
channel = YoutubeChannel("EmbeddedHow")
channel.subscribe(YoutubeUser("sub1"))
channel.subscribe(YoutubeUser("sub2"))
channel.subscribe(YoutubeUser("sub3"))
channel.notify("A new video released")
Below is the output after the EmbeddedHow YouTube channel uploads a new video and triggers the notify() method to inform all the subscribers that the new video has been released.
User sub1 recived notification from EmbeddedHow : A new video released
User sub2 recived notification from EmbeddedHow : A new video released
User sub3 recived notification from EmbeddedHow : A new video released
The key benefits of the Observer Pattern are:
Loose Coupling: It promotes loose coupling between the subject and its observers. The subject doesn't need to know the specifics of its observers, and observers don't need to know the details of the subject's implementation. This separation allows for easier maintenance and extension.
Scalability: You can easily add or remove observers without modifying the subject. This makes it simple to extend the functionality of a system without changing the core subject class.
Event Handling: The Observer Pattern is commonly used in event-driven programming and graphical user interface frameworks. Events, such as button clicks or mouse movements, are often implemented using this pattern.
Decoupling Push and Pull Models: Observers can be implemented to either pull the data they need from the subject when they're notified, or the subject can push data to the observers. This flexibility allows you to tailor the pattern to different use cases.
Where Observer pattern is used?
The Observer Pattern is used in various software systems and applications to handle situations where objects need to maintain a one-to-many dependency relationship, such as notifying multiple observers when a specific event or state change occurs. Here are some common use cases for the Observer Pattern:
User Interface Frameworks: Observer patterns are widely used in graphical user interfaces (GUIs) and event-driven programming. For example, in a windowing system, user interface elements like buttons, checkboxes, and text fields can be observers that respond to user interactions.
Distributed Systems: In distributed systems, the Observer Pattern is used to notify multiple components about changes or events occurring in the system. For instance, in a publish-subscribe messaging system, subscribers are observers that receive updates from publishers.
Stock Market Applications: Financial applications often use the Observer Pattern to update multiple clients or users about changes in stock prices, news, or market conditions in real-time.
Weather Monitoring Systems: Weather monitoring systems employ this pattern. Weather sensors act as subjects, and displays showing temperature, humidity, and pressure act as observers that update when weather conditions change.
Event Handling: Whenever you have events in your software system that can be triggered by user interactions (e.g., button clicks, keyboard presses, mouse movements), you can use the Observer Pattern to handle these events. Event listeners and handlers are observers who respond to these events.
Game Development: Video games often use the Observer Pattern for various in-game events, such as player actions, enemy movements, or game state changes. Game objects can register as observers and respond to these events.
Traffic Management Systems: In intelligent transportation systems, traffic lights, sensors, and control units can use the Observer Pattern to coordinate traffic flow and adapt to changing conditions.
Monitoring and Logging Systems: In applications that require monitoring and logging of events, the Observer Pattern can be used to notify and log various events and system conditions.
Chat Applications: In chat applications, users can subscribe to chat rooms or conversations. When a new message is sent to a chat room, all participants (observers) are notified of the new message.
Comments