Con el patrón observer, podemos suscribir ciertos objetos, los observadores, a otro objeto llamado el observable. ¡Cada vez que ocurre un evento, el observable notifica a todos sus observadores!
Un patrón observer generalmente contiene 2 partes importantes:
Suscriptores: Un array de listeners que están suscritos a las notificaciones del notificador. Realizan la acción con la cual se subscribieron en respuesta a las notificaciones emitidas por el notificador. Todas estas clases deben implementar la misma interfaz de forma que el notificador no esté acoplado a clases concretas.Notificador: Envía eventos de interés a otros objetos. Esos eventos ocurren cuando el notificador cambia su estado o ejecuta algunos comportamientos. Los notificadores también contienen una infraestructura de suscripción que permite a nuevos y antiguos suscriptores abandonar la lista.subscribe(): un método para agregar suscriptores a la lista de suscriptores.unsubscribe(): un método para eliminar suscriptores de la lista de suscriptores.notify(): un método para notificar a todos los suscriptores cada vez que ocurre un evento específico.
Utilizar el patrón observador aporta varias ventajas:
- Principio de
abierto/cerrado. Puedes introducir nuevas clases suscriptoras sin tener que cambiar el código de la clase notificador (y viceversa si hay una interfaz notificador). - Puedes establecer relaciones entre objetos durante el tiempo de ejecución.
Puedes experimentar este problema a menudo al trabajar con clases de la interfaz gráfica de usuario. Por ejemplo, si creaste clases personalizadas de botón y quieres permitir al cliente colgar código cliente de tus botones para que se active cuando un usuario pulse un botón.
El patrón Observer permite que cualquier objeto que implemente la interfaz suscriptora pueda suscribirse a notificaciones de eventos en objetos observables o notificadores. Puedes añadir el mecanismo de suscripción a tus botones, permitiendo a los clientes acoplar su código personalizado a través de clases suscriptoras personalizadas.
classDiagram
direction TB
class Subscriber {
+listen()
}
class Observer {
- subscribers: Subscriber[]
+subscribe(subscriber: Subscriber) void
+unsubscribe(subscriber: Subscriber) void
+notify(data: Data) : void
}
class SubscriberOne {
+listen()
}
class SubscriberTwo {
+listen()
}
<<Class>> Subscriber
<<Class>> Observer
<<Subscriber>> SubscriberOne
<<Subscriber>> SubscriberTwo
SubscriberOne --|> Subscriber : Inheritance
SubscriberTwo --|> Subscriber : Inheritance
Subscriber --> Observer : Association
Observer ..|> SubscriberTwo : NotifyAllSubscribers
Observer ..|> SubscriberOne : NotifyAllSubscribers
interface Subscriber<D = string> {
listen(data: D): void;
}
class Observer<D = string> {
private subscribers: Subscriber<D>[] = [];
constructor() {}
public subscribe(subscriber: Subscriber<D>): void {
this.subscribers.push(subscriber);
}
public unsubscribe(subscriber: Subscriber<D>): void {
this.subscribers = this.subscribers.filter((s) => s !== subscriber);
}
public notify(data: D): void {
this.subscribers.forEach((subscriber: Subscriber<D>) => {
subscriber.listen(data);
});
}
}
class SubscriberOne implements Subscriber<string> {
listen(data: string): void {
console.log('LOG: One has been notified about: ' + data);
}
}
class SubscriberTwo implements Subscriber<string> {
listen(data: string): void {
console.info('INFO: Two has been notified about: ' + data);
}
}
const subscriberOne = new SubscriberOne();
const subscriberTwo = new SubscriberTwo();
const publisher = new Observer<string>();
publisher.subscribe(subscriberOne);
publisher.subscribe(subscriberTwo);
publisher.notify('Hello World!');Output:
LOG: One has been notified about: Hello World!
INFO: Two has been notified about: Hello World!
interface Subscriber<D = string> {
listen(data: D): void;
}
class Observer<D = string> {
private subscribers: Subscriber<D>[] = [];
constructor() {}
public subscribe(subscriber: Subscriber<...