Lección 8.4 : Patron de diseño Observer
Patrón de Diseño Observer en Python
Introducción
¡Hola a todos! Soy Yuscu Mejía y en esta lección vamos a explorar el concepto del patrón de diseño Observer en Python. Este patrón es fundamental para establecer una relación de suscripción entre objetos, donde un objeto notifica a otros objetos sobre cualquier cambio en su estado.
Características
El patrón de diseño Observer en Python tiene las siguientes características:
- Define una dependencia uno-a-muchos entre objetos, de manera que cuando un objeto cambia su estado, todos sus dependientes son notificados y actualizados automáticamente.
- Facilita la comunicación entre objetos en un sistema de manera desacoplada.
- Permite añadir nuevos observadores sin modificar el código del sujeto.
- Es útil en la implementación de eventos y manejadores de eventos.
Propósito
El patrón de diseño Observer permite definir una relación de suscripción entre objetos, donde un objeto (el sujeto) notifica a otros objetos (los observadores) sobre cualquier cambio en su estado.
Problema
El problema que resuelve el patrón Observer es el de permitir que los objetos se mantengan sincronizados sin estar estrechamente acoplados, facilitando la extensibilidad y el mantenimiento del código.
Solución
La solución propuesta por el patrón Observer es utilizar una interfaz común para los observadores y permitir que el sujeto mantenga una lista de sus observadores. Cuando el sujeto cambia su estado, notifica a todos los observadores registrados.
Analogía en el Mundo Real
Una analogía del mundo real sería una aplicación de noticias. Cuando una nueva noticia se publica, todos los usuarios suscritos reciben una notificación de la nueva noticia.
Estructura
La estructura del patrón Observer incluye los siguientes componentes:
- Subject: Mantiene una lista de observadores y proporciona métodos para agregar, eliminar y notificar observadores.
- Observer: Interfaz común para todos los observadores que define el método de actualización.
- ConcreteSubject: Implementación concreta del sujeto.
- ConcreteObserver: Implementaciones concretas de los observadores.

Aplicabilidad
El patrón Observer es aplicable cuando:
- Una abstracción tiene dos aspectos, uno dependiente del otro.
- Se requiere que un cambio en un objeto provoque cambios en otros sin establecer explícitamente dependencias.
- Se desea que los objetos puedan suscribirse o darse de baja dinámicamente.
Pros y Contras
- Pros:
- Facilita la comunicación entre objetos de manera desacoplada.
- Permite añadir nuevos observadores sin modificar el código del sujeto.
- Promueve la reutilización del código y la separación de responsabilidades.
- Contras:
- Puede introducir complejidad adicional debido a la gestión de la lista de observadores.
- Los observadores pueden quedar desincronizados si no se manejan adecuadamente las notificaciones.
Vamos a ver el uso del Patrón Observer
A continuación, un ejemplo de cómo utilizar el patrón Observer en Python, presentado por Yuscu Mejía:
-
- Patrón Observer:
# Definir una clase Sujeto
class Sujeto:
def __init__(self):
self._observadores = []
def agregar_observador(self, observador):
self._observadores.append(observador)
def eliminar_observador(self, observador):
self._observadores.remove(observador)
def notificar_observadores(self):
for observador in self._observadores:
observador.actualizar(self)
# Definir una clase Observador (Abstracta)
from abc import ABC, abstractmethod
class Observador(ABC):
@abstractmethod
def actualizar(self, sujeto):
pass
# Implementar clases concretas de Observadores
class Alarma(Observador):
def __init__(self, umbral):
self.umbral = umbral
def actualizar(self, sujeto):
if sujeto.get_temperatura() > self.umbral:
self.alertar(sujeto.get_temperatura())
def alertar(self, temperatura):
pass
class AlarmaSonora(Alarma):
def alertar(self, temperatura):
print(f"¡Alarma Sonora! Temperatura alta: {temperatura}")
class AlarmaVisual(Alarma):
def alertar(self, temperatura):
print(f"¡Alarma Visual! Temperatura alta: {temperatura}")
# Definir una clase SensorTemperatura
class SensorTemperatura(Sujeto):
def __init__(self):
super().__init__()
self._temperatura = 0
def get_temperatura(self):
return self._temperatura
def set_temperatura(self, valor):
self._temperatura = valor
self.notificar_observadores()
# Crear una instancia de SensorTemperatura
sensor = SensorTemperatura()
# Crear instancias de Alarmas
alarma_sonora = AlarmaSonora(30)
alarma_visual = AlarmaVisual(25)
# Agregar observadores al sensor
sensor.agregar_observador(alarma_sonora)
sensor.agregar_observador(alarma_visual)
# Cambiar la temperatura y notificar a los observadores
sensor.set_temperatura( 20 ) # No se activa ninguna alarma
sensor.set_temperatura(28) # Se activa la alarma visual
sensor.set_temperatura(35) # Se activan ambas alarmas
Práctica
Para practicar, les invito a ver nuestro tutorial en video sobre el patrón de diseño Observer en Python, presentado por Yuscu Mejía:
Recorda si te gusta los videos, te agradeceria si le pones un comentario o un like para saber si subir mas videos! 😮
Si no sabes que comentar, comenta con: estoy avanzando rapido con el curso de Programacion python 🙂 asi te detectaremos que viniste de aca, para una estadistica si conviene o no subir videos

Ejercicio
Ahora les propongo un ejercicio para aplicar lo que hemos aprendido sobre el patrón de diseño Observer en Python, con la guía de Yuscu Mejía:
Ejercicio: Implementar el Patrón Observer con Alarmas Abstractas
Vamos a crear una clase llamada SensorHumedad que actúe como sujeto y otra clase abstracta llamada Alarma. Implementaremos dos subclases de Alarma llamadas AlarmaSonora y AlarmaVisual que se activarán cuando la humedad supere ciertos umbrales.
#Ejercicio
# Definir una clase Sujeto
class SensorHumedad:
def __init__(self):
self._observadores = []
self._humedad = 0
def agregar_observador(self, observador):
self._observadores.append(observador)
def eliminar_observador(self, observador):
self._observadores.remove(observador)
def notificar_observadores(self):
for observador in self._observadores:
observador.actualizar(self)
@property
def humedad(self):
return self._humedad
@humedad.setter
def humedad(self, valor):
self._humedad = valor
self.notificar_observadores()
# Definir una clase Observador (Abstracta)
from abc import ABC, abstractmethod
class Alarma(ABC):
def __init__(self, umbral):
self.umbral = umbral
@abstractmethod
def actualizar(self, sujeto):
pass
class AlarmaSonora(Alarma):
def actualizar(self, sujeto):
if sujeto.humedad > self.umbral:
self.alertar(sujeto.humedad)
def alertar(self, humedad):
print(f"¡Alarma Sonora! Humedad alta: {humedad}")
class AlarmaVisual(Alarma):
def actualizar(self, sujeto):
if sujeto.humedad > self.umbral:
self.alertar(sujeto.humedad)
def alertar(self, humedad):
print(f"¡Alarma Visual! Humedad alta: {humedad}")
# Crear una instancia de SensorHumedad
sensor_humedad = SensorHumedad()
# Crear instancias de Alarmas
alarma_sonora = AlarmaSonora(60)
alarma_visual = AlarmaVisual(50)
# Agregar observadores al sensor
sensor_humedad.agregar_observador(alarma_sonora)
sensor_humedad.agregar_observador(alarma_visual)
# Cambiar la humedad y notificar a los observadores
sensor_humedad.humedad = 45 # No se activa ninguna alarma
sensor_humedad.humedad = 55 # Se activa la alarma visual
sensor_humedad.humedad = 65 # Se activan ambas alarmas

