Menu
Coddy logo textTech

Patrón Observer

Parte de la sección Programación Orientada a Objetos del Journey de C++ de Coddy. Lección 94 de 104.

El patrón Observer define una dependencia de uno a muchos entre objetos: cuando un objeto (el sujeto) cambia de estado, todos sus dependientes (los observadores) reciben una notificación automáticamente. Esto es ideal para sistemas de eventos, actualizaciones de la interfaz de usuario o cualquier escenario en el que varios objetos deban reaccionar a los cambios.

El patrón implica dos roles clave: un sujeto que mantiene una lista de observadores y les notifica, y observadores que implementan una interfaz de actualización:

#include <iostream>
#include <vector>
#include <algorithm>

class Observer {
public:
    virtual void update(int value) = 0;
    virtual ~Observer() = default;
};

class Subject {
    std::vector<Observer*> observers;
    int state = 0;
    
public:
    void attach(Observer* obs) {
        observers.push_back(obs);
    }
    
    void detach(Observer* obs) {
        observers.erase(
            std::remove(observers.begin(), observers.end(), obs),
            observers.end());
    }
    
    void setState(int value) {
        state = value;
        notify();
    }
    
    void notify() {
        for (Observer* obs : observers) {
            obs->update(state);
        }
    }
};

class Display : public Observer {
    std::string name;
public:
    Display(const std::string& n) : name(n) {}
    void update(int value) override {
        std::cout << name << " received: " << value << "\n";
    }
};

int main() {
    Subject sensor;
    Display screen1("Screen1"), screen2("Screen2");
    
    sensor.attach(&screen1);
    sensor.attach(&screen2);
    sensor.setState(42);  // Ambos displays notificados
}

Cuando se llama a setState(), el sujeto recorre todos los observadores registrados y llama a su método update(). Los observadores pueden conectarse o desconectarse en cualquier momento, lo que hace que el sistema sea flexible y esté débilmente acoplado.

Usa Observer cuando los cambios en un objeto requieran actualizar otros y no quieras que estos objetos estén estrechamente acoplados.

challenge icon

Desafío

Fácil

Construyamos un sistema de monitoreo de una estación meteorológica utilizando el patrón Observer. Crearás una estación meteorológica que registra los datos de temperatura y notifica automáticamente a varias unidades de visualización cada vez que cambia la temperatura: una aplicación clásica de este patrón en el mundo real.

Organizarás tu código en tres archivos:

  • Observer.h: Define la interfaz del observador y un observador de visualización concreto.

    Crea una clase abstracta Observer con un método virtual puro update(double temperature) que los observadores implementan para recibir notificaciones, junto con un destructor virtual.

    Después crea una clase TemperatureDisplay que herede de Observer. Cada pantalla tiene un nombre (string) establecido mediante su constructor. Cuando se llama a update(), debe imprimir:

    [DisplayName]: Temperature is [temperature] degrees
  • WeatherStation.h: Crea el sujeto que mantiene la temperatura y notifica a los observadores.

    Tu clase WeatherStation debe:

    • Almacenar una lista de punteros a observadores y la temperatura actual (inicializada en 0.0)
    • Tener un método attach(Observer* obs) para registrar observadores
    • Tener un método detach(Observer* obs) para eliminar observadores
    • Tener un método setTemperature(double temp) que actualice la temperatura y notifique a todos los observadores asociados
    • Tener un método privado notify() que llame a update() en cada observador con la temperatura actual
  • main.cpp: Demuestra el patrón Observer en acción.

    Lee tres entradas:

    1. Nombre de la primera pantalla (string)
    2. Nombre de la segunda pantalla (string)
    3. Un valor de temperatura (double)

    Crea una WeatherStation y dos objetos TemperatureDisplay con los nombres proporcionados. Asocia ambas pantallas a la estación y después establece la temperatura en el valor de entrada. Ambas pantallas deben recibir automáticamente la actualización e imprimir sus mensajes.

    Después de eso, separa la primera pantalla y establece una nueva temperatura que sea 5 grados mayor que la entrada. Solo la segunda pantalla debe recibir esta actualización.

Por ejemplo, con las entradas Kitchen, Bedroom y 22.5:

Kitchen: Temperature is 22.5 degrees
Bedroom: Temperature is 22.5 degrees
Bedroom: Temperature is 27.5 degrees

Con las entradas Office, Lobby y 18.0:

Office: Temperature is 18 degrees
Lobby: Temperature is 18 degrees
Lobby: Temperature is 23 degrees

Observa cómo el patrón Observer crea un sistema débilmente acoplado: la estación meteorológica no necesita saber nada sobre las pantallas específicas; simplemente notifica a quien esté escuchando. Cuando separas un observador, deja de recibir actualizaciones automáticamente.

Pruébalo tú mismo

#include <iostream>
#include <string>
#include "WeatherStation.h"

using namespace std;

int main() {
    // Leer entradas
    string display1Name, display2Name;
    double temperature;
    
    cin >> display1Name;
    cin >> display2Name;
    cin >> temperature;
    
    // TODO: Crear un objeto WeatherStation
    
    // TODO: Crear dos objetos TemperatureDisplay con los nombres de entrada
    
    // TODO: Adjuntar ambas pantallas a la estación meteorológica
    
    // TODO: Establecer la temperatura al valor de entrada
    // (Ambas pantallas deberían imprimir sus mensajes)
    
    // TODO: Desadjuntar la primera pantalla
    
    // TODO: Establecer la temperatura a 5 grados más alta que la de entrada
    // (Solo la segunda pantalla debería imprimir)
    
    return 0;
}
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

Practica por tu cuenta: Compilador de C++ online