Un patrón de diseño es una plantilla que resuelve un problema recurrente en el diseño de software.

El patrón de observador, también conocido como patrón de publicación-suscripción, es un patrón de comportamiento. Le permite notificar a múltiples objetos o suscriptores sobre cualquier evento que se publique en el objeto que están observando.

Aquí aprenderá a implementar el patrón de diseño del observador en TypeScript.

El patrón del observador

El patrón de observador funciona definiendo una relación de uno a muchos entre el editor y sus suscriptores. Cuando ocurre un evento en el editor, notificará a todos los suscriptores de ese evento. Un ejemplo generalizado de este patrón es Oyentes de eventos de JavaScript.

Por contexto, suponga que está creando un rastreador de inventario que realiza un seguimiento de la cantidad de productos en su tienda. En este caso, su tienda es el sujeto/editor y su inventario es el observador/suscriptor. Usar el patrón de diseño del observador sería óptimo en esta situación.

instagram viewer

En el patrón de diseño del observador, su clase de sujeto debe implementar tres métodos:

  • Un adjuntar método. Este método añade un observador al sujeto.
  • A despegar método. Este método elimina un observador de un sujeto.
  • A notificar/actualizar método. Este método notifica a los observadores del sujeto cuando cambia el estado del sujeto.

Su clase de observador debe implementar un método, el actualizar método. Este método reacciona cuando hay un cambio en el estado de su sujeto.

Implementando las Clases Sujeto y Observador

El primer paso para implementar este patrón es crear interfaces para la clase sujeto y observador, para garantizar que implementen los métodos correctos:

// Interfaz de sujeto/editor
interfazSujeto{
adjuntarObservador (observador: observador): vacío;
detachObserver (observador: observador): vacío;
notificarObserver(): vacío;
}

// Interfaz de observador/suscriptor
interfazObservador{
actualizar(asunto: Asunto): vacío;
}

Las interfaces en el bloque de código anterior definen los métodos que deben implementar sus clases concretas.

Una clase de materia concreta

El siguiente paso es implementar una clase de sujeto concreto que implemente el Sujeto interfaz:

// Sujeto
claseAlmacenarimplementosSujeto{}

A continuación, inicialice el Sujetoestado en el Almacenar clase. Los observadores del sujeto reaccionarán a los cambios en este estado.

En este caso, el estado es un número, y los observadores reaccionarán ante un aumento en el número:

// Estado del sujeto
privado numeroDeProductos: numero;

A continuación, inicialice una matriz de observadores. Esta matriz es cómo harás un seguimiento de los observadores:

// inicializando observadores
privado observadores: Observador[] = [];

Puede encontrar algunas implementaciones del patrón de observador usando una estructura de datos establecida en lugar de una matriz para realizar un seguimiento del observador. El uso de un conjunto garantizará que el mismo observador no aparezca dos veces. Si desea utilizar una matriz en su lugar, debe buscar observadores duplicados en su adjuntar método.

A continuación, debe implementar el SujetoLos métodos de—adjuntar, despegar, y notificar/actualizar—en tu clase concreta.

Para implementar el adjuntar método, primero verifique si el observador ya está conectado y arroje un error si lo está. De lo contrario, agregue el observador a la matriz usando el método de matriz de JavaScript, empujar:

// Adjuntar observador(es)
adjuntarObservador (observador: observador): vacío {
// Comprobar si el observador ya se ha adjuntado
constante observador existe = este.observadores.incluye (observador);

si (existe el observador) {
tirarnuevoError('El observador ya se ha suscrito');
}

// Agregar un nuevo observador
este.observadores.empujar(observador);
}

A continuación, implemente su despegar método encontrando el índice y eliminándolo de la matriz usando JavaScript empalme método.

Puede haber escenarios en los que el observador que está intentando desconectar ya se haya desconectado o no estaba suscrito en primer lugar. Debe manejar estos escenarios agregando una declaración condicional para verificar si el observador está en la matriz o en el conjunto, según sea el caso.

// Separación de observador(es)
detachObserver (observador: observador): vacío {
consola.registro(`Separación del observador ${JSON.stringify (observador)}`);
constante índiceobservador = este.observadores.indexOf (observador);

si (índice de observador -1) {
tirarnuevoError('El observador no existe');
}

este.observadores.empalme(índice de observador, 1);
consola.log('Observador separado...');
}

A continuación, implemente su notificar/actualizar método recorriendo su lista de observadores y llamando al actualizar método de cada uno:

// Notificar a los observadores
notificarObserver(): vacío {
consola.log('Notificando a los observadores...');

para (constante observador deeste.observadores) {
observador.actualizar(este);
}
}

Finalmente, para el Sujeto clase, implemente un método que manipule el estado y luego notifique a los observadores del cambio llamando a su notificar/actualizar método. Este ejemplo es una simplificación de cómo un sujeto puede realizar una acción y luego informar a los observadores:

// Cambiando de estado y notificando a los observadores
nuevoProducto (productos: número): vacío {
este.numberOfProducts += productos;
consola.log('Nuevo producto añadido a la tienda.');
este.notificar al observador();
}

Clases de observadores concretos

Cree una clase o clases de observador para suscribirse al editor. Cada clase de observador debe implementar el Observador interfaz.

Las clases de observador implementarán un notificar/actualizar método que sólo el sujeto que están observando debe llamar. Este método debe contener toda la lógica comercial que necesita para ejecutar en respuesta a un cambio en el estado del sujeto:

// Observador concreto 1
claseInventarioimplementosObservador{
actualizar(): vacío {
consola.log('Nuevo producto agregado a la tienda, actualizando inventario...');
// La lógica comercial actual va aquí...
}
}

// Observador concreto 2
claseClienteimplementosObservador{
actualizar(): vacío {
consola.log('Nuevo producto agregado a la tienda, tengo que ir a verlo...');
// La lógica comercial actual va aquí...
}
}

Uso del patrón de observador

Para usar este patrón, crea una instancia del sujeto concreto y las clases de observador. Una vez que lo haya hecho, llame al Sujeto adjuntar y pase la instancia de Observer como argumento. En respuesta, el sujeto agregará esa instancia a su lista de observadores:

// Instanciando Sujeto y Observador
constante tienda = nuevo Almacenar();
constante inventario = nuevo Inventario();
constante cliente = nuevo Cliente()

// Suscribiendo objetos al editor
almacenar.adjuntarObservador(inventario);
almacenar.adjuntarObservador(cliente);
// Cambiando el estado del sujeto
almacenar.nuevo producto(30);

Este código simula un cambio de estado. El cambio activará el método de notificación en el Sujeto clase. Este método, a su vez, llama al notificar método en cada uno de sus observadores. Luego, cada observador ejecutará su propia lógica comercial.

Solo debe usar este patrón cuando los cambios en el estado de un objeto afectan a otros objetos, y el conjunto de objetos involucrados es desconocido o dinámico.

Ventajas de usar el patrón de observador

El uso de este patrón en su código le permite mantener el principio de apertura/cierre. Puede agregar tantos suscriptores como desee y establecer relaciones entre objetos en tiempo de ejecución, sin cambiar el código del sujeto.