El patrón de diseño Observer
Descripción
El patrón de diseño Observer tiene como objetivo modelizar una dependencia entre un sujeto y los observadores de modo que cada modificación del estado interno del sujeto sea notificada a sus observadores para que puedan actualizar su estado.
Ejemplo
Queremos actualizar la visualización de un catálogo de vehículos en tiempo real. Cada vez que la información relativa a un vehículo se modifica, queremos actualizar la visualización de la misma. Puede haber varias visualizaciones simultáneas.
La solución recomendada por el patrón de diseño Observer consiste en establecer un enlace entre cada vehículo y sus vistas para que el vehículo pueda indicarles que se actualicen cuando su estado interno haya sido modificado. Esta solución se ilustra en la figura 24.1.
Figura 24.1 - El patrón de diseño Observer aplicado a la visualización de vehículos
El diagrama contiene las cuatro clases o interfaces siguientes:
-
Sujeto es la clase abstracta que incluye todo objeto que notifica a los demás objetos de las modificaciones en su estado interno.
-
Vehículo es la subclase concreta de Sujeto que describe a los vehículos. Gestiona dos atributos: descripción y precio.
-
Observador es la interfaz de todo objeto que necesite recibir las notificaciones de cambio de estado provenientes de los objetos a los que se ha inscrito previamente.
-
VistaVehiculo es la subclase concreta correspondiente a la implementación de Observador cuyas instancias muestran la información de un vehículo.
El funcionamiento es el siguiente: cada nueva vista se inscribe como observador...
Estructura
1. Diagrama de clases
La figura 24.3 detalla la estructura genérica del patrón de diseño Observer.
Figura 24.3 - Estructura del patrón de diseño Observer
2. Participantes
Los participantes del patrón de diseño Observer son los siguientes:
-
Sujeto(AbstractSujeto) es la clase abstracta que incluye la asociación con los observadores así como los métodos para agregar o suprimir observadores.
-
Observador(ObservadorInterfaz) es la interfaz que es necesario implementar para recibir las notificaciones (método actualiza).
-
SujetoConcreto (Vehiculo) es una clase correspondiente a la implementación de un sujeto. Un sujeto envía una notificación cuando su estado interno se ha modificado.
-
ObservadorConcreto (VistaVehiculo) es una clase de implementación de un observador. Mantiene una referencia hacia el sujeto e implementa el método actualiza. Solicita a su sujeto información que forma parte de su estado durante las actualizaciones invocando al método getEstado.
3. Colaboraciones
El sujeto notifica a sus observadores cuando su estado interno ha sido modificado. Cuando un observador recibe esta notificación, se actualiza en consecuencia. Para realizar esta actualización, puede invocar a los métodos del sujeto que dan acceso a su estado.
Dominios de aplicación
El patrón de diseño Observer se utiliza en los casos siguientes:
-
Una modificación en el estado de un objeto genera modificaciones en otros objetos que se determinan dinámicamente.
-
Un objeto quiere avisar a otros objetos sin tener que conocer su tipo, es decir sin estar fuertemente acoplado a ellos.
-
No se desea fusionar dos objetos en uno solo.
Ejemplo en PHP
Retomamos el ejemplo de la figura 24.1. El código fuente de la clase AbstractSujeto aparece a continuación. Los observadores se gestionan mediante una matriz.
<?php
declare(strict_types=1);
namespace ENI\DesignPatterns\Observer;
abstract class AbstractSujeto
{
protected array $observadores = [];
public function agrega(ObservadorInterfaz $observador): void
{
$this->observadores[] = $observador;
}
public function retira(ObservadorInterfaz $observador): void
{
$key = array_search($observador, $this->observadores);
if (false !== $key) {
unset($this->observadores[$key]);
}
}
public function notifica(): void
{
foreach ($this->observadores as $observador) {
$observador->actualiza();
} ...