Menu
Coddy logo textTech

Patrón Observer

Parte de la sección Programación Orientada a Objetos del Journey de Java de Coddy — lección 68 de 87.

El Patrón Observer es un patrón de diseño de comportamiento que establece una relación de uno a muchos entre objetos. Cuando un objeto (el sujeto) cambia de estado, todos sus dependientes (los observadores) son notificados y actualizados automáticamente. Piense en ello como una suscripción a un boletín informativo: los suscriptores reciben actualizaciones cada vez que se publica contenido nuevo.

El patrón involucra dos componentes principales: un sujeto que mantiene una lista de observadores y les notifica los cambios, y observadores que definen un método de actualización para responder a las notificaciones:

import java.util.ArrayList;
import java.util.List;

interface Observer {
    void update(String message);
}

class NewsPublisher {
    private List<Observer> subscribers = new ArrayList<>();
    
    public void subscribe(Observer observer) {
        subscribers.add(observer);
    }
    
    public void unsubscribe(Observer observer) {
        subscribers.remove(observer);
    }
    
    public void publish(String news) {
        for (Observer subscriber : subscribers) {
            subscriber.update(news);
        }
    }
}

class EmailSubscriber implements Observer {
    private String email;
    
    public EmailSubscriber(String email) {
        this.email = email;
    }
    
    public void update(String message) {
        System.out.println("Email to " + email + ": " + message);
    }
}

Cuando el editor publica noticias, todos los suscriptores son notificados automáticamente:

NewsPublisher publisher = new NewsPublisher();
publisher.subscribe(new EmailSubscriber("alice@mail.com"));
publisher.subscribe(new EmailSubscriber("bob@mail.com"));

publisher.publish("Breaking news!");
// Salida:
// Email para alice@mail.com: Breaking news!
// Email para bob@mail.com: Breaking news!

El patrón Observer promueve el acoplamiento débil: el sujeto no necesita conocer las clases concretas de sus observadores, solo que implementan la interfaz Observer. Esto facilita la adición de nuevos tipos de observadores sin modificar el sujeto.

challenge icon

Desafío

Fácil

¡Vamos a construir un sistema de alerta de precios de acciones utilizando el Patrón Observer! Crearás un sistema donde un marcador de acciones (stock ticker) notifica a múltiples inversores cada vez que el precio de la acción cambia, permitiendo que cada inversor reaccione a las actualizaciones de precios a su manera.

Organizarás tu código en cuatro archivos:

  • Observer.java: Define la interfaz Observer que todos los inversores implementarán. Debe declarar un único método update(String stockName, double price) que los observadores utilizan para recibir notificaciones sobre cambios de precio.
  • StockTicker.java: Crea la clase sujeto que mantiene una lista de observadores y les notifica los cambios de precio. Tu StockTicker debe tener:

    Un campo String privado para el nombre de la acción (establecido a través del constructor).

    Un campo double privado para el precio actual (inicialmente 0).

    Una lista privada para almacenar a los observadores suscritos.

    Un método subscribe(Observer observer) que añade un observador a la lista.

    Un método unsubscribe(Observer observer) que elimina un observador de la lista.

    Un método setPrice(double price) que actualiza el precio y luego notifica a todos los observadores llamando a su método update con el nombre de la acción y el nuevo precio.

  • Investors.java: Crea dos tipos diferentes de inversores que implementen la interfaz Observer:

    DayTrader - tiene un campo de nombre privado establecido a través del constructor. Cuando se actualiza, imprime [name] received alert: [stockName] is now $[price] - Making quick trade!

    LongTermInvestor - tiene un campo de nombre privado establecido a través del constructor. Cuando se actualiza, imprime [name] received alert: [stockName] is now $[price] - Holding steady.

    Formatea el precio con dos decimales.

  • Main.java: ¡Une tu sistema de observadores! Recibirás tres entradas: el nombre de la acción (String), la primera actualización de precio (double) y la segunda actualización de precio (double).

    Crea un StockTicker con el nombre de la acción dado. Crea un DayTrader llamado "Alice" y un LongTermInvestor llamado "Bob", y suscribe a ambos al marcador.

    Establece el precio al primer valor de entrada (todos los observadores son notificados). Luego, cancela la suscripción de Alice. Finalmente, establece el precio al segundo valor de entrada (solo Bob debería ser notificado esta vez).

Recibirás tres entradas en orden: nombre de la acción (String), primer precio (double), segundo precio (double).

Este desafío demuestra el poder del Patrón Observer: el StockTicker no sabe nada sobre los tipos específicos de inversores; solo sabe que implementan Observer. Cuando cancelas la suscripción de Alice, ella deja de recibir actualizaciones mientras que Bob continúa siendo notificado. ¡Este acoplamiento débil facilita la adición de nuevos tipos de inversores sin cambiar el marcador!

Hoja de referencia

El Patrón Observer es un patrón de diseño de comportamiento que establece una relación de uno a muchos entre objetos. Cuando un objeto (el sujeto) cambia de estado, todos sus dependientes (los observadores) son notificados y actualizados automáticamente.

El patrón involucra dos componentes principales:

  • Sujeto: Mantiene una lista de observadores y les notifica los cambios
  • Observadores: Definen un método de actualización para responder a las notificaciones

Estructura básica:

import java.util.ArrayList;
import java.util.List;

interface Observer {
    void update(String message);
}

class Subject {
    private List<Observer> observers = new ArrayList<>();
    
    public void subscribe(Observer observer) {
        observers.add(observer);
    }
    
    public void unsubscribe(Observer observer) {
        observers.remove(observer);
    }
    
    public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}

class ConcreteObserver implements Observer {
    public void update(String message) {
        // Reaccionar a la notificación
    }
}

Ejemplo de uso:

Subject subject = new Subject();
subject.subscribe(new ConcreteObserver());
subject.notifyObservers("State changed!");
// Todos los observadores suscritos reciben la actualización

El Patrón Observer promueve el acoplamiento débil: el sujeto no necesita conocer las clases concretas de sus observadores, solo que implementan la interfaz Observer. Esto facilita la adición de nuevos tipos de observadores sin modificar el sujeto.

Pruébalo tú mismo

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Leer entradas
        String stockName = scanner.nextLine();
        double firstPrice = scanner.nextDouble();
        double secondPrice = scanner.nextDouble();
        
        // TODO: Crear un StockTicker con el stockName dado
        
        // TODO: Crear un DayTrader llamado "Alice"
        
        // TODO: Crear un LongTermInvestor llamado "Bob"
        
        // TODO: Suscribir tanto a Alice como a Bob al ticker
        
        // TODO: Establecer el precio a firstPrice (ambos observadores son notificados)
        
        // TODO: Desuscribir a Alice
        
        // TODO: Establecer el precio a secondPrice (solo Bob es notificado)
        
        scanner.close();
    }
}
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