Patrón Observer
Parte de la sección Programación orientada a objetos del Journey de Python de Coddy. Lección 47 de 64.
El patrón Observer crea una relación de uno a muchos en la que un objeto (sujeto) notifica a varios objetos (observadores) cuando cambia su estado.
Aquí tienes una clase Subject sencilla que gestiona observadores:
class Subject:
def __init__(self):
self._observers = []
def add_observer(self, observer):
self._observers.append(observer)
def notify(self, message):
for observer in self._observers:
observer.update(message)El sujeto mantiene una lista de observadores y puede notificarlos a todos a la vez.
Crea clases observadoras sencillas:
class EmailNotifier:
def update(self, message):
print(f"Email sent: {message}")
class SMSNotifier:
def update(self, message):
print(f"SMS sent: {message}")Cada observador tiene un método update que se llama cuando recibe una notificación.
Usa el patrón observador:
# Crear sujeto
news = Subject()
# Crear observadores
email = EmailNotifier()
sms = SMSNotifier()
# Añadir observadores al sujeto
news.add_observer(email)
news.add_observer(sms)
# Notificar a todos los observadores
news.notify("Breaking news: Python is awesome!")Crea un ejemplo práctico con un rastreador de precios de acciones:
class Stock:
def __init__(self, symbol, price):
self.symbol = symbol
self._price = price
self._observers = []
def add_observer(self, observer):
self._observers.append(observer)
def set_price(self, price):
self._price = price
self.notify()
def notify(self):
for observer in self._observers:
observer.update(self.symbol, self._price)
class Investor:
def __init__(self, name):
self.name = name
def update(self, symbol, price):
print(f"{self.name} notified: {symbol} is now ${price}")
# Usa el rastreador de acciones
apple_stock = Stock("AAPL", 150)
investor1 = Investor("Alice")
investor2 = Investor("Bob")
apple_stock.add_observer(investor1)
apple_stock.add_observer(investor2)
apple_stock.set_price(155) # Notifica a todos los inversoresSalida:
Email sent: Breaking news: Python is awesome!
SMS sent: Breaking news: Python is awesome!
Alice notified: AAPL is now $155
Bob notified: AAPL is now $155Punto clave: el patrón Observer permite que un objeto notifique automáticamente a muchos otros cuando algo cambia. El sujeto mantiene una lista de observadores y llama a su método update cuando es necesario. Esto resulta útil para las notificaciones, los sistemas de eventos y para mantener sincronizadas varias partes de tu aplicación.
Desafío
IntermedioImplementa el patrón Observer creando un sistema de monitoreo meteorológico. Debes crear dos clases en las áreas designadas del código.
Paso 1: Crea la clase WeatherStation
Escribe tu clase WeatherStation donde lo indique el comentario. Esta clase debe:
- Heredar de la clase Subject (usa
class WeatherStation(Subject):) - Inicializarse con:
- Llama al constructor de la clase padre usando
super().__init__() - Establece la temperatura inicial en 0 usando un atributo con un solo guion bajo,
self._temperature(la convención de Python para un atributo interno)
- Llama al constructor de la clase padre usando
- Implementar
<strong>set_temperature(self, temperature)</strong>:- Actualiza el atributo de temperatura interno
- Llama a
self.notify(self._temperature)para notificar a todos los observadores
- Implementar
<strong>get_temperature(self)</strong>:- Devuelve el valor actual de la temperatura
Paso 2: Crea la clase WeatherDisplay
Escribe tu clase WeatherDisplay donde lo indique el comentario. Esta clase debe:
- Heredar de la clase Observer (usa
class WeatherDisplay(Observer):) - Inicializarse con:
- Aceptar un parámetro
name - Almacenar el nombre como
self.name
- Aceptar un parámetro
- Implementar
<strong>update(self, temperature)</strong>:- Imprimir el mensaje de actualización de temperatura exactamente en el formato que se muestra a continuación
Formato del mensaje:
Cuando una pantalla recibe una actualización de temperatura, debe imprimir exactamente:
Display [name]: Current temperature is [temperature]CEjemplo de uso:
# Crear estación meteorológica y pantallas
station = WeatherStation()
phone_display = WeatherDisplay("Phone")
tablet_display = WeatherDisplay("Tablet")
# Adjuntar pantallas a la estación
station.attach(phone_display)
station.attach(tablet_display)
# Actualizar temperatura - ambas pantallas serán notificadas
station.set_temperature(25.5)
# Salida:
# Display Phone: Current temperature is 25.5C
# Display Tablet: Current temperature is 25.5CNotas importantes:
- Los métodos
attach()ydetach()ya están implementados en la clase base Subject; no necesitas implementarlos ni llamarlos en tu clase WeatherStation - En el ejemplo de uso anterior,
station.attach(phone_display)es llamado por el usuario de tu clase, no dentro de tu implementación de WeatherStation - Tu WeatherStation solo necesita llamar a
self.notify()cuando cambie la temperatura; la clase base Subject se encarga del resto - Concéntrate en implementar los tres métodos requeridos en WeatherStation y los dos métodos requeridos en WeatherDisplay, tal como se especifica arriba
Pruébalo tú mismo
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, data):
for observer in self._observers:
observer.update(data)
class Observer:
def update(self, data):
pass
# Escribe tu clase WeatherStation aquí
# Escribe tu clase WeatherDisplay aquí
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación orientada a objetos
1Fundamentos de la POO
Archivos externosIntroducción a la POOClases vs ObjetosEl parámetro selfMétodosAtributosMétodo constructor (__init__)Resumen - Calculadora simple4Herencia
Herencia básicaLa función super()Sobrescritura de métodosHerencia múltipleOrden de resolución de métodosResumen - Jerarquía de empleados7Métodos especiales
Introducción a los métodos mágicosSobrecarga de operadoresMétodos mágicos de contenedoresRepaso - Lista personalizada10Patrones de diseño Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy2Decoradores
Introducción a los decoradoresDecorador propertyDecorador de métodos estáticosDecorador de métodos de clase5Polimorfismo
Sobreescritura de métodos revisitadaDuck TypingClases y métodos abstractosDiseño de interfacesResumen - Calculadora de figuras8Conceptos avanzados de POO
Composición vs. HerenciaMixinsMétodos estáticos y de claseDecoradores de claseGestores de contexto11Patrones de diseño, parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón Composite3Propiedades de clase
Variables de instancia vs de claseDecoradores de propiedadesAtributos privadosResumen - Gestor de cuentas bancariasPractica por tu cuenta: Compilador de Python online