Menu
Coddy logo textTech

Patrón Observer (Eventos)

Parte de la sección Programación Orientada a Objetos del Journey de C# de Coddy — lección 54 de 70.

El patrón Observer establece una relación de uno a muchos donde un objeto (el sujeto) notifica a múltiples objetos dependientes (observadores) cuando su estado cambia. En C#, los eventos proporcionan una forma integrada de implementar este patrón de manera elegante.

El patrón involucra a un publicador que emite eventos y suscriptores que responden a ellos. Aquí hay un ejemplo práctico de un monitor de precios de acciones:

public class Stock
{
    private decimal _price;
    
    public event Action<decimal> PriceChanged;
    
    public decimal Price
    {
        get => _price;
        set
        {
            _price = value;
            PriceChanged?.Invoke(_price);  // Notificar a todos los observadores
        }
    }
}

public class PriceAlert
{
    public void OnPriceChanged(decimal newPrice)
    {
        Console.WriteLine($"Alert: Price is now {newPrice}");
    }
}

public class PriceLogger
{
    public void OnPriceChanged(decimal newPrice)
    {
        Console.WriteLine($"Logged: {newPrice}");
    }
}

Los suscriptores asocian sus métodos al evento utilizando += y pueden desvincularlos con -=:

var stock = new Stock();
var alert = new PriceAlert();
var logger = new PriceLogger();

stock.PriceChanged += alert.OnPriceChanged;
stock.PriceChanged += logger.OnPriceChanged;

stock.Price = 150.50m;
// Salida:
// Alerta: El precio ahora es 150.50
// Registrado: 150.50

stock.PriceChanged -= logger.OnPriceChanged;  // Cancelar suscripción
stock.Price = 155.00m;
// Salida: Alerta: El precio ahora es 155.00

El patrón Observer promueve el acoplamiento débil: la clase Stock no necesita saber nada sobre sus observadores. Nuevos observadores pueden suscribirse sin modificar al publicador, lo que hace que el sistema sea fácil de extender y mantener.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de monitoreo de temperatura utilizando el patrón Observer con eventos. Crearás un sensor que notifica a múltiples observadores cada vez que la temperatura cambia, lo cual es perfecto para escenarios como sistemas de control climático donde diferentes componentes necesitan reaccionar a las actualizaciones de temperatura.

Organizarás tu código en tres archivos:

  • TemperatureSensor.cs: Crea una clase TemperatureSensor en el espacio de nombres Monitoring. Este es tu publicador: el sujeto que otros objetos observarán. Tu sensor debe tener:
    • Un campo privado para almacenar la temperatura actual
    • Un evento llamado TemperatureChanged que utiliza Action<double> para notificar a los suscriptores sobre la nueva temperatura
    • Una propiedad Temperature que activa el evento cada vez que se establece la temperatura a un nuevo valor
  • Observers.cs: Crea dos clases observadoras en el mismo espacio de nombres que se suscribirán a los cambios de temperatura:
    • DisplayUnit: tiene un método OnTemperatureChanged(double temp) que imprime Display: {temp}C
    • AlarmSystem: tiene un método OnTemperatureChanged(double temp) que imprime Alarm Check: {temp}C
  • Program.cs: Une todo creando un sensor y ambos observadores. Suscribe ambos observadores al evento del sensor y luego actualiza la temperatura. Después de eso, desuscribe el sistema de alarma y actualiza la temperatura nuevamente para mostrar que solo la unidad de visualización recibe la notificación.

Recibirás dos entradas:

  • Primera lectura de temperatura (por ejemplo, 22.5)
  • Segunda lectura de temperatura (por ejemplo, 28.0)

Tu programa debe:

  1. Crear el sensor y ambos observadores
  2. Suscribir ambos observadores al evento TemperatureChanged
  3. Establecer la temperatura del sensor al primer valor de entrada (ambos observadores deben ser notificados)
  4. Desuscribir el AlarmSystem del evento
  5. Establecer la temperatura del sensor al segundo valor de entrada (solo el display debe ser notificado)

Por ejemplo, si las entradas son 22.5 y 28.0, la salida debería ser:

Display: 22.5C
Alarm Check: 22.5C
Display: 28C

Esto demuestra el poder central del patrón Observer: el sensor no sabe ni le importa quién lo está escuchando. Los observadores pueden suscribirse y desuscribirse dinámicamente, ¡y el publicador simplemente notifica a quien esté escuchando en ese momento!

Hoja de referencia

El patrón Observer establece una relación de uno a muchos donde un objeto (el sujeto) notifica a múltiples objetos dependientes (observadores) cuando su estado cambia.

En C#, los eventos proporcionan una forma integrada de implementar este patrón. El patrón involucra a un publicador que emite eventos y suscriptores que responden a ellos.

Implementación básica de eventos

Define un evento usando event Action<T> e invócalo cuando el estado cambie:

public class Stock
{
    private decimal _price;
    
    public event Action<decimal> PriceChanged;
    
    public decimal Price
    {
        get => _price;
        set
        {
            _price = value;
            PriceChanged?.Invoke(_price);  // Notificar a todos los observadores
        }
    }
}

Creación de observadores

Los observadores son clases con métodos que coinciden con la firma del evento:

public class PriceAlert
{
    public void OnPriceChanged(decimal newPrice)
    {
        Console.WriteLine($"Alert: Price is now {newPrice}");
    }
}

public class PriceLogger
{
    public void OnPriceChanged(decimal newPrice)
    {
        Console.WriteLine($"Logged: {newPrice}");
    }
}

Suscripción y cancelación de suscripción

Usa += para suscribirte y -= para cancelar la suscripción a los eventos:

var stock = new Stock();
var alert = new PriceAlert();
var logger = new PriceLogger();

stock.PriceChanged += alert.OnPriceChanged;    // Suscribirse
stock.PriceChanged += logger.OnPriceChanged;   // Suscribirse

stock.Price = 150.50m;  // Ambos observadores notificados

stock.PriceChanged -= logger.OnPriceChanged;   // Cancelar suscripción

stock.Price = 155.00m;  // Solo la alerta es notificada

El patrón Observer promueve el acoplamiento débil: el publicador no necesita saber nada sobre sus observadores. Nuevos observadores pueden suscribirse sin modificar el publicador.

Pruébalo tú mismo

using System;
using Monitoring;

class Program
{
    public static void Main(string[] args)
    {
        // Leer las temperaturas de entrada
        double temp1 = Convert.ToDouble(Console.ReadLine());
        double temp2 = Convert.ToDouble(Console.ReadLine());

        // TODO: Crear una instancia de TemperatureSensor

        // TODO: Crear instancias de DisplayUnit y AlarmSystem

        // TODO: Suscribir ambos observadores al evento TemperatureChanged

        // TODO: Establecer la temperatura del sensor a temp1 (ambos observadores notificados)

        // TODO: Desuscribir el AlarmSystem del evento

        // TODO: Establecer la temperatura del sensor a temp2 (solo el display notificado)
    }
}
quiz iconPonte a prueba

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