Aprende a aplicar el Observer Pattern para lograr gestión flexible de suscripciones y actualización automática ante eventos. Ideal cuando necesitas un servicio de notificación en sistemas con múltiples receptores, con una estructura clara: manager, listeners y un método update que centraliza la reacción a cambios.
¿Qué es el patrón observer y para qué sirve?
El Observer Pattern es un patrón de diseño de comportamiento que resuelve la notificación de eventos a múltiples interesados sin acoplarlos entre sí. Se utiliza para implementar un servicio de eventos simple y efectivo, ampliamente adoptado por su practicidad y facilidad.
¿Cómo se organiza la arquitectura con listeners y manager?
Clase manager: agrega, remueve y notifica a todos los listeners.
Interfaz listener: define el método update(evento: cualquier tipo).
Implementaciones de listener: servicios como email y login que reaccionan en su método update.
Clase principal: incluye al manager como atributo; por ejemplo, un servicio de pagos que llama a notifyAll cuando hay que notificar.
¿Cuándo aplicarlo en sistemas de eventos?
Se recomienda cuando:
Un cambio debe notificar a múltiples objetos de forma automática.
Se implementa un sistema de eventos con receptores independientes.
Se necesitan mecanismos de suscripción y notificación simples y claros.
¿Qué beneficios inmediatos aporta?
Gestión flexible de suscripciones y receptores.
Actualización automática ante nuevos eventos.
Simplicidad en la integración de nuevos listeners.
¿Cómo implementarlo paso a paso?
Aplica esta secuencia mínima:
Define una interfaz Listener con un método de notificación: update(evento).
Crea una clase manager que gestione listeners: agregar, remover y notifyAll.
Agrega el manager como atributo de la clase de alto nivel (por ejemplo, el servicio de pagos) y úsalo para notificar.
// 1) Interfaz ListenerinterfaceListener{update(event:any):void;}// 2) Clase manager (gestiona suscriptores y notificaciones)classEventManager{private listeners:Listener[]=[];add(listener:Listener):void{this.listeners.push(listener);}remove(listener:Listener):void{this.listeners=this.listeners.filter(l => l !== listener);}notifyAll(event:any):void{this.listeners.forEach(l => l.update(event));}}// Implementaciones de Listener (servicios que reaccionan al evento)classEmailListenerimplementsListener{update(event:any):void{// Lógica de notificación por email.}}classLoginListenerimplementsListener{update(event:any):void{// Lógica relacionada con login.}}// 3) Clase de alto nivel con el manager como atributo (servicio de pagos)classPaymentsService{private manager =newEventManager();constructor(){this.manager.add(newEmailListener());this.manager.add(newLoginListener());}procesarPago():void{// ... lógica de pago.this.manager.notifyAll(/* evento */undefined);}}
¿Qué habilidades y conceptos refuerza?
Uso de interfaces y clases para contratos claros.
Diseño de sistemas de eventos con suscripción y notificación.
Implementación de listeners como servicios: email y login.
Estructuración de una clase de alto nivel con atributo manager y método notifyAll.
¿Has aplicado el patrón Observer en tus proyectos? Compártelo en comentarios y cuéntanos tu caso de uso.
En mi proyecto de bot de trading, uso un WebsocketManager que gestiona las conexiones las suscripciones de los websockets así como creación y eliminación de los mismos y las suscripciones a los streams.
La estrategia usa estos para notificar por consolar y por mensaje de telegram.
Este escenario es factible para este patrón, me queda la duda?
uso colas asíncronas que van guardando los mensajes en la cola y la estrategia las va analizando
sí es porque en este caso tienes diferentes sitios a los que tienes que notificar (consola y telegram), este patrón te permite definir un solo lugar donde gestionar las notificaciones que debes hacer
Tu escenario es factible para el Patrón Observer. El WebsocketManager actuaría como el "Manager" que notifica los eventos, y tu estrategia de trading con sus notificaciones (consola, Telegram) serían los "Listeners" que reaccionan a esos eventos. Las colas asíncronas encajan para gestionar esos mensajes.
El **Patrón Observer** es un patrón de diseño de comportamiento que define una relación de dependencia entre objetos, de manera que cuando un objeto cambia de estado (el *subject*), todos los objetos que dependen de él (los *observers*) son notificados automáticamente.
Este patrón es útil para escenarios donde múltiples objetos deben reaccionar a los cambios en otro objeto sin acoplarse estrechamente.
### Ejemplo Clásico: Sistema de Notificaciones
Vamos a implementar un sistema donde varios *observers* (como usuarios o servicios) sean notificados cuando un sistema de pagos cambie de estado, por ejemplo, cuando se procese un pago.
### Paso 1: Definir el Subject
El **Subject** es el objeto principal al que los observadores se suscriben.
def attach(self, observer): """Agrega un observer a la lista.""" self.\_observers.append(observer)
def detach(self, observer): """Elimina un observer de la lista.""" self.\_observers.remove(observer)
def notify(self, message): """Notifica a todos los observers.""" for observer in self.\_observers: observer.update(message)```
\### Paso 2: Definir la Interfaz del Observer
Cada \*\*Observer\*\* debe implementar un método `update` que será llamado por el Subject.
```pythonfrom abc import ABC, abstractmethod
class Observer(ABC): @abstractmethod def update(self, message): pass```
\### Paso 3: Implementar Observers Concretos
Crea clases concretas que implementen la interfaz del Observer.
```pythonclass EmailNotifier(Observer): def update(self, message): print(f"EmailNotifier: Enviando email con el mensaje: '{message}'")
class SMSNotifier(Observer): def update(self, message): print(f"SMSNotifier: Enviando SMS con el mensaje: '{message}'")
class LogNotifier(Observer): def update(self, message): print(f"LogNotifier: Registrando en el log: '{message}'")```
\### Paso 4: Usar el Patrón Observer
Ahora conectemos todo. Supongamos que tenemos un sistema de pagos que notifica a los observadores cuando un pago se procesa.
```pythonclass PaymentSystem(Subject): def process\_payment(self, amount, method): print(f"Procesando pago de {amount} usando {method}.") self.notify(f"Pago de {amount} procesado con {method}.")```
\#### Código Principal
```python# Crear un sistema de pagospayment\_system = PaymentSystem()
\# Crear observersemail\_notifier = EmailNotifier()sms\_notifier = SMSNotifier()log\_notifier = LogNotifier()
\# Suscribir observers al sistema de pagospayment\_system.attach(email\_notifier)payment\_system.attach(sms\_notifier)payment\_system.attach(log\_notifier)
\# Procesar un pagopayment\_system.process\_payment(100, "Tarjeta de Crédito")
\# Desuscribir un observerpayment\_system.detach(sms\_notifier)
\# Procesar otro pagopayment\_system.process\_payment(200, "PayPal")```
\### Salida Esperada
\*\*Primer pago (todos los observers suscritos):\*\*```Procesando pago de 100 usando Tarjeta de Crédito.EmailNotifier: Enviando email con el mensaje: 'Pago de 100 procesado con Tarjeta de Crédito.'SMSNotifier: Enviando SMS con el mensaje: 'Pago de 100 procesado con Tarjeta de Crédito.'LogNotifier: Registrando en el log: 'Pago de 100 procesado con Tarjeta de Crédito.'```
\*\*Segundo pago (SMSNotifier desuscrito):\*\*```Procesando pago de 200 usando PayPal.EmailNotifier: Enviando email con el mensaje: 'Pago de 200 procesado con PayPal.'LogNotifier: Registrando en el log: 'Pago de 200 procesado con PayPal.'```
\### Ventajas del Patrón Observer
1\. \*\*Desacoplamiento\*\*: Los *\*subjects\** no necesitan conocer los detalles de implementación de los *\*observers\**.2. \*\*Flexibilidad\*\*: Puedes añadir o eliminar *\*observers\** en tiempo de ejecución.3. \*\*Reutilización\*\*: Los *\*observers\** pueden ser reutilizados en diferentes *\*subjects\**.
\### Aplicaciones Reales
1\. \*\*Interfaces de usuario\*\*: Notificación de cambios en un modelo a vistas o controladores.2. \*\*Sistemas de eventos\*\*: Como el patrón *\*pub-sub\** en sistemas de mensajería.3. \*\*Notificaciones en tiempo real\*\*: Servicios como websockets o push notifications.
\### Conclusión
El \*\*Patrón Observer\*\* es una solución robusta para implementar sistemas donde un objeto central (como un sistema de pagos) necesita informar a otros objetos sobre sus cambios de estado. Su implementación en Python es simple y aprovecha características como listas dinámicas para gestionar observadores de manera eficiente.