Patrón Observador

El patrón observador es un patrón de diseño de comportamiento que define una relación de dependencia de uno a muchos. Cuando el estado de un objeto cambia, todos sus dependientes reciben una notificación y se actualizan automáticamente.

Cuando existe una relación de uno a muchos entre objetos, se utiliza el patrón observador (Observer Pattern). Por ejemplo, cuando un objeto es modificado, automáticamente notifica a los objetos que dependen de él. El patrón observador pertenece a los patrones de comportamiento.

Introducción

Intención

Crea una relación de dependencia de uno a muchos entre objetos. Cuando el estado de un objeto cambia, todos los objetos que dependen de él reciben una notificación y se actualizan automáticamente.

Problema principal que resuelve

  • El patrón observador resuelve el problema de cómo notificar automáticamente a otros objetos dependientes cuando el estado de un objeto cambia, manteniendo al mismo tiempo un bajo acoplamiento y una alta colaboración entre objetos.

Escenarios de uso

  • Cuando un cambio de estado de un objeto necesita actualizar simultáneamente otros objetos.

Método de implementación

  • Definir la interfaz del observador: contiene un método de actualización.
  • Crear observadores concretos: implementan la interfaz del observador y definen el comportamiento al recibir una notificación.
  • Definir la interfaz del sujeto: contiene métodos para agregar, eliminar y notificar a los observadores.
  • Crear sujetos concretos: implementan la interfaz del sujeto, gestionan la lista de observadores y les notifican cuando cambia el estado.

Código clave

  • Lista de observadores: se mantiene una lista de observadores en el sujeto.

Ejemplos de aplicación

  • Sistema de subastas: el subastador actúa como sujeto, los postores como observadores; cuando el precio de la subasta se actualiza, se notifica a todos los postores.
  • Historia de Viaje al Oeste: el Bodhisattva rocía agua como cambio de estado, y la tortuga vieja, como observador, observa este cambio.

Ventajas

  • Acoplamiento abstracto: entre el observador y el sujeto existe un acoplamiento abstracto.
  • Mecanismo de activación: se establece un mecanismo de activación y notificación para cuando cambia el estado.

Desventajas

  • Problemas de rendimiento: si hay muchos observadores, el proceso de notificación puede llevar tiempo.
  • Dependencia circular: puede provocar llamadas circulares y fallos del sistema.
  • Falta de detalles del cambio: el observador no sabe cómo cambia el sujeto, solo sabe que ocurrió el cambio.

Recomendaciones de uso

  • Úselo cuando se necesite reducir el acoplamiento entre objetos y cuando los cambios de estado de un objeto deban desencadenar cambios en otros objetos.
  • Considere usar las clases de soporte integradas de Java para el patrón observador, comojava.util.Observableyjava.util.Observer。

Notas

  • Evitar referencias circulares: preste atención a la relación de dependencia entre observador y sujeto para evitar referencias circulares.
  • Ejecución asíncrona: considere usar notificaciones asíncronas para evitar que un único punto de fallo bloquee todo el sistema.

Estructura

El patrón observador incluye los siguientes roles principales:

  • Sujeto (Subject): también llamado observado u observable, es un objeto con estado y mantiene una lista de observadores. El sujeto proporciona métodos para agregar, eliminar y notificar a los observadores.
  • Observador (Observer): es el objeto que recibe las notificaciones del sujeto. El observador debe implementar un método de actualización; cuando recibe la notificación del sujeto, llama a dicho método para realizar la actualización.
  • Sujeto concreto (Concrete Subject): es la clase de implementación concreta del sujeto. Mantiene la lista de observadores y les notifica cuando cambia su estado.
  • Observador concreto (Concrete Observer): es la clase de implementación concreta del observador. Implementa el método de actualización y define las operaciones concretas que debe ejecutar al recibir la notificación del sujeto.

El patrón observador logra un acoplamiento flojo entre objetos al desacoplar el sujeto y el observador. Cuando el estado del sujeto cambia, todos los observadores que dependen de él reciben la notificación y realizan la actualización correspondiente.

Implementación

El patrón observador utiliza tres clases: Subject, Observer y Client. El objeto Subject tiene métodos para vincular observadores al objeto Client y desvincularlos del objeto Client. CreamosSubjectla clase,Observerla clase abstracta y extienden la clase abstractaObserverlas clases de entidad.

ObserverPatternDemo, nuestra clase de demostración usaSubjecty objetos de clases de entidad para demostrar el patrón observador.

观察者模式的 UML 图

Paso 1

Cree la clase Subject.

Subject.java

import java.util.ArrayList; import java.util.List; public class Subject { private List<Observer> observers = new ArrayList<Observer>(); private int state; public int getState() { return state; } public void setState(int state) { this.state = state; notifyAllObservers(); } public void attach(Observer observer){ observers.add(observer); } public void notifyAllObservers(){ for (Observer observer : observers) { observer.update(); } } }

Paso 2

Cree la clase Observer.

Observer.java

public abstract class Observer { protected Subject subject; public abstract void update(); }

Paso 3

Cree las clases de observadores concretos.

BinaryObserver.java

public class BinaryObserver extends Observer{ public BinaryObserver(Subject subject){ this.subject = subject; this.subject.attach(this); } @Override public void update() { System.out.println( "Binary String: " + Integer.toBinaryString( subject.getState() ) ); } }

OctalObserver.java

public class OctalObserver extends Observer{ public OctalObserver(Subject subject){ this.subject = subject; this.subject.attach(this); } @Override public void update() { System.out.println( "Octal String: " + Integer.toOctalString( subject.getState() ) ); } }

HexaObserver.java

public class HexaObserver extends Observer{ public HexaObserver(Subject subject){ this.subject = subject; this.subject.attach(this); } @Override public void update() { System.out.println( "Hex String: " + Integer.toHexString( subject.getState() ).toUpperCase() ); } }

Paso 4

UseSubjecty objetos de observadores concretos.

ObserverPatternDemo.java

public class ObserverPatternDemo { public static void main(String[] args) { Subject subject = new Subject(); new HexaObserver(subject); new OctalObserver(subject); new BinaryObserver(subject); System.out.println("First state change: 15"); subject.setState(15); System.out.println("Second state change: 10"); subject.setState(10); } }

Paso 5

Ejecute el programa y muestre el resultado:

First state change: 15
Hex String: F
Octal String: 17
Binary String: 1111
Second state change: 10
Hex String: A
Octal String: 12
Binary String: 1010
Otras extensiones