DEV Community

daniellupaca
daniellupaca

Posted on

Understanding and Implementing the Observer Pattern in Software Development

Introduction

The Observer pattern is a fundamental behavioral design pattern in software engineering that allows a subscription mechanism to notify multiple objects of any event that occurs to the object they are observing. This pattern is also known by various names such as Observer, Publish-Subscription, Model-View, Event-Subscribe, and Listener.

Problem Scenario

Consider a scenario that involves two types of objects: a Customer object and a Store object. The customer is very interested in a specific brand of product, such as a new iPhone model, which will soon be available in the store. The customer could visit the store daily to check the availability of the product, but most of these trips would be in vain until the product is actually available. On the other hand, the store could send hundreds of emails to all customers every time a new product becomes available, saving customers unnecessary travel but at the same time, potentially annoying other customers not interested in the new products.

Observer Pattern Solution

The Observer pattern addresses this problem by suggesting that you add a subscription mechanism to the notifier class so that individual objects can subscribe or unsubscribe from an event stream of that notifier.

Real-World Example

A practical example of the Observer pattern is a system of interaction between customers and stores:

  • Notifier: The store that sends notifications about product availability.
  • Subscriber: The customer who receives updates about the products of their interest.

Code Example

Definition of Classes

Here we define the 'Notifier' and 'Subscriber' classes. The 'Notifier' class manages a list of subscribers and notifies each of them when an event occurs. The 'Subscriber' class simply prints the message it receives.

The Notifier class acts as the publisher (or subject) in the Observer pattern. This class is responsible for keeping a list of their observers and notifying them when something important happens.

class Notificador:
    def __init__(self):
        self._observadores = []

    def suscribir(self, observador):
        self._observadores.append(observador)

    def desuscribir(self, observador):
        self._observadores.remove(observador)

    def notificar(self, mensaje):
        for observador in self._observadores:
            observador.actualizar(mensaje)
Enter fullscreen mode Exit fullscreen mode


python

The Subscriber class represents the observers in this pattern. Each subscriber who wants to receive notifications from the Notifier must implement this class.

class Suscriptor:
    def actualizar(self, mensaje):
        print(f"Actualización recibida: {mensaje}")
Enter fullscreen mode Exit fullscreen mode


python

Instantiating Classes

Finally, let's look at how these components interact in a usage example.

tienda = Notificador()
cliente = Suscriptor()
Enter fullscreen mode Exit fullscreen mode


python

Customer subscription to store notifications

tienda.suscribir(cliente)
Enter fullscreen mode Exit fullscreen mode


python

Notification of the availability of a new product

tienda.notificar("¡El nuevo modelo de iPhone ya está disponible!")
Enter fullscreen mode Exit fullscreen mode


python

Advantages of the Observer Pattern

Weak Coupling

The notifier doesn't need to know anything about subscribers. This allows the components of the system to be more independent of each other, making it easier to maintain and evolve.

Dynamic Relationships

New subscribers can join or leave at any time without the notifier needing to change. This makes the system highly adaptable and scalable to future changes.

Conclusion

The Observer pattern is particularly useful in situations where an object needs to notify other objects about changes in its state, without knowing who these objects are. It promotes a clear separation of concerns and a well-organized architecture in applications.

By implementing the Observer pattern, software developers can create flexible, maintainable code that efficiently handles dynamic relationships between objects, making it ideal for managing complex dependencies in software applications.

Top comments (0)