Introducción

El patrón de diseño Observer es un patrón de comportamiento que define una relación de dependencia uno a muchos entre objetos, de manera que cuando un objeto cambia su estado, todos sus dependientes son notificados y actualizados automáticamente. Este patrón es especialmente útil en situaciones donde un cambio en un objeto debe reflejarse en otros objetos sin que estos estén estrechamente acoplados.

Conceptos Clave

  • Sujeto (Subject): El objeto que mantiene una lista de dependientes (observadores) y notifica a estos cuando cambia su estado.
  • Observador (Observer): El objeto que desea ser notificado cuando el sujeto cambia su estado.
  • Notificación: El proceso mediante el cual el sujeto informa a los observadores sobre los cambios en su estado.

Estructura

La estructura del patrón Observer se puede desglosar en los siguientes componentes:

  1. Subject: Interfaz o clase abstracta que define los métodos para agregar, eliminar y notificar observadores.
  2. ConcreteSubject: Implementación concreta del Subject. Mantiene el estado del que los observadores dependen.
  3. Observer: Interfaz o clase abstracta que define el método update que será llamado cuando el Subject cambie.
  4. ConcreteObserver: Implementación concreta del Observer. Actualiza su estado para mantenerse consistente con el Subject.

Diagrama UML

+----------------+       +-----------------+
|    Subject     |       |    Observer     |
+----------------+       +-----------------+
| +attach()      |       | +update()       |
| +detach()      |       +-----------------+
| +notify()      |
+----------------+
        ^
        |
        |
+------------------+
| ConcreteSubject  |
+------------------+
| -state           |
| +getState()      |
| +setState()      |
+------------------+
        ^
        |
        |
+------------------+
| ConcreteObserver |
+------------------+
| -subject         |
| -observerState   |
| +update()        |
+------------------+

Ejemplo Práctico

Vamos a implementar un ejemplo práctico en Python para ilustrar cómo funciona el patrón Observer.

Código

Subject.py

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

    def attach(self, observer):
        self._observers.append(observer)

    def detach(self, observer):
        self._observers.remove(observer)

    def notify(self):
        for observer in self._observers:
            observer.update(self)

ConcreteSubject.py

class ConcreteSubject(Subject):
    def __init__(self):
        super().__init__()
        self._state = None

    @property
    def state(self):
        return self._state

    @state.setter
    def state(self, value):
        self._state = value
        self.notify()

Observer.py

class Observer:
    def update(self, subject):
        pass

ConcreteObserver.py

class ConcreteObserver(Observer):
    def __init__(self, name):
        self._name = name

    def update(self, subject):
        print(f"{self._name} has been notified. New state is: {subject.state}")

Main.py

if __name__ == "__main__":
    subject = ConcreteSubject()

    observer1 = ConcreteObserver("Observer 1")
    observer2 = ConcreteObserver("Observer 2")

    subject.attach(observer1)
    subject.attach(observer2)

    subject.state = "State 1"
    subject.state = "State 2"

Explicación del Código

  1. Subject: Define los métodos attach, detach y notify para gestionar la lista de observadores.
  2. ConcreteSubject: Implementa el Subject y mantiene el estado. Cuando el estado cambia, se llama al método notify para actualizar a los observadores.
  3. Observer: Define el método update que será llamado cuando el Subject cambie.
  4. ConcreteObserver: Implementa el método update para realizar la acción deseada cuando se notifica un cambio en el Subject.
  5. Main: Crea instancias de ConcreteSubject y ConcreteObserver, y demuestra cómo los observadores son notificados cuando cambia el estado del sujeto.

Ejercicio Práctico

Ejercicio

Implementa un sistema de notificaciones para una aplicación de noticias. Cuando se publica una nueva noticia, todos los suscriptores deben ser notificados.

Requisitos

  1. Crea una clase NewsPublisher que actúe como el Subject.
  2. Crea una clase Subscriber que actúe como el Observer.
  3. Los suscriptores deben ser notificados con el título de la nueva noticia.

Solución

NewsPublisher.py

class NewsPublisher:
    def __init__(self):
        self._subscribers = []
        self._latest_news = None

    def attach(self, subscriber):
        self._subscribers.append(subscriber)

    def detach(self, subscriber):
        self._subscribers.remove(subscriber)

    def notify(self):
        for subscriber in self._subscribers:
            subscriber.update(self)

    def add_news(self, news):
        self._latest_news = news
        self.notify()

    @property
    def latest_news(self):
        return self._latest_news

Subscriber.py

class Subscriber:
    def __init__(self, name):
        self._name = name

    def update(self, publisher):
        print(f"{self._name} received news: {publisher.latest_news}")

Main.py

if __name__ == "__main__":
    publisher = NewsPublisher()

    subscriber1 = Subscriber("Subscriber 1")
    subscriber2 = Subscriber("Subscriber 2")

    publisher.attach(subscriber1)
    publisher.attach(subscriber2)

    publisher.add_news("Breaking News: Observer Pattern in Action!")
    publisher.add_news("Update: Observer Pattern Example Completed!")

Explicación de la Solución

  1. NewsPublisher: Actúa como el Subject, manteniendo una lista de suscriptores y notificándolos cuando se publica una nueva noticia.
  2. Subscriber: Actúa como el Observer, recibiendo notificaciones con el título de la nueva noticia.
  3. Main: Demuestra cómo los suscriptores son notificados cuando se publica una nueva noticia.

Conclusión

El patrón Observer es una herramienta poderosa para gestionar dependencias uno a muchos entre objetos, permitiendo que los cambios en un objeto se reflejen automáticamente en otros sin un acoplamiento estrecho. Este patrón es ampliamente utilizado en sistemas de notificación, interfaces de usuario y cualquier situación donde un cambio en un objeto debe ser comunicado a múltiples dependientes.

Al dominar el patrón Observer, estarás mejor preparado para diseñar sistemas flexibles y mantenibles que respondan eficientemente a cambios en el estado de los objetos.

© Copyright 2024. Todos los derechos reservados