Chain of responsability y Observer pattern en JavaScript
Chain of responsability pattern 🔗
El patrón Chain of Responsibility en JavaScript es un patrón de diseño que permite la distribución de responsabilidades entre múltiples objetos. Este patrón permite que varios objetos puedan manejar una solicitud sin tener que conocer a quién se está enviando la solicitud ni cuál es el objeto que la manejará finalmente.
La aplicación del patrón Chain of Responsibility en JavaScript se logra a través de la creación de una cadena de objetos que se comunican entre sí. Cada objeto de la cadena debe tener una referencia al siguiente objeto en la cadena y debe tener la capacidad de manejar la solicitud si lo desea. Si un objeto no puede manejar la solicitud, la pasa al siguiente objeto en la cadena.
Ejemplo de aplicación del patrón Chain of Responsibility en JavaScript:
// Clase base para las solicitudesclassSolicitud{constructor(tipo, cantidad){this.tipo= tipo;this.cantidad= cantidad;this.siguiente=null;}}// Clase manejadora de solicitudes de descuentosclassDescuentoHandler{constructor(){this.siguiente=null;}solicitar(solicitud){if(solicitud.tipo==="descuento"){console.log(`Se aplicó un descuento del 10% por un total de ${solicitud.cantidad*0.1}`);}elseif(this.siguiente!==null){this.siguiente.solicitar(solicitud);}}}// Clase manejadora de solicitudes de envío gratisclassEnvioGratisHandler{constructor(){this.siguiente=null;}solicitar(solicitud){if(solicitud.cantidad>=500){console.log("Se aplicó envío gratis");}elseif(this.siguiente!==null){this.siguiente.solicitar(solicitud);}}}// Usoconst descuentoHandler =newDescuentoHandler();const envioGratisHandler =newEnvioGratisHandler();descuentoHandler.siguiente= envioGratisHandler;const solicitud =newSolicitud("descuento",100);descuentoHandler.solicitar(solicitud);// Se aplicó un descuento del 10% por un total de 10const solicitud2 =newSolicitud("compra normal",700);descuentoHandler.solicitar(solicitud2);// Se aplicó envío gratis
Código corregido por @Energy 💚
En este ejemplo, creamos dos clases manejadoras de solicitudes, DescuentoHandler y EnvioGratisHandler, que se encargan de manejar solicitudes específicas. Luego, establecemos una relación de cadena entre ellos, estableciendo que DescuentoHandler es el primer objeto en la cadena y EnvioGratisHandler es el siguiente.
Cuando se hace una solicitud, se inicia en DescuentoHandler, que verifica si puede manejar la solicitud. Si no puede, pasa la solicitud al siguiente objeto en la cadena, EnvioGratisHandler, que verifica si puede manejarla. Si uno de los objetos en la cadena puede manejar la solicitud, se ejecuta su lógica correspondiente y se detiene la cadena. De lo contrario, la solicitud se pierde y no se ejecuta ninguna acción.
Este patrón es útil en situaciones donde una sola clase no debería ser responsable de manejar todas las solicitudes, y en lugar de eso, se deben dividir entre varios objetos. Además, permite que la lógica de manejo de solicitudes sea fácilmente modificable y escalable, ya que se pueden agregar o eliminar objetos de la cadena sin afectar el comportamiento de los objetos existentes.
Observer pattern 👀
El patrón Observer en JavaScript es un patrón de diseño que permite que un objeto mantenga una lista de sus dependientes y notifique a ellos automáticamente cualquier cambio. Este patrón es útil cuando necesitamos que varios objetos reciban notificaciones de cambios en un objeto determinado.
La aplicación del patrón Observer en JavaScript se logra a través de la creación de un objeto que mantiene una lista de sus dependientes y provee una forma de registrarlos y notificarlos de los cambios. Cada objeto dependiente debe tener una función que se ejecute cada vez que se produzca un cambio en el objeto principal.
Ejemplo de aplicación del patrón Observer en JavaScript:
// Clase ObservadorclassObservador{constructor(nombre){this.nombre= nombre;}notificar(cambio){console.log(`${this.nombre} ha sido notificado del cambio: ${cambio}`);}}// Clase ObservableclassObservable{constructor(){this.observadores=[];}registrarObservador(observador){this.observadores.push(observador);}notificarCambio(cambio){this.observadores.forEach(observador=>{ observador.notificar(cambio);});}}// Usoconst observable =newObservable();const observador1 =newObservador("Observador 1");const observador2 =newObservador("Observador 2");observable.registrarObservador(observador1);observable.registrarObservador(observador2);observable.notificarCambio("Cambio en el objeto principal");// Observador 1 ha sido notificado del cambio: Cambio en el objeto principal// Observador 2 ha sido notificado del cambio: Cambio en el objeto principal
En este ejemplo, creamos una clase Observador y una clase Observable. La clase Observable mantiene una lista de sus dependientes (observadores) y provee una forma de registrarlos y notificarlos de los cambios. Cada vez que se produce un cambio en el objeto principal, se notifica a todos los observadores registrados.
El ejemplo de la cadena de responsabilidad no está correcto.
Lo he corregido para que funcione como debería de funcionar:
Mis modificaciones:
Renombramiento de los métodos de la linea 16 y 31 deberían de ser el mismo, es decir, llamarse por ejemplo 'solicitar()' y en la linea 20 y 35 realizar la llamada así: this.siguiente.solicitar(solicitud)
De esta manera se encadenan con el mismo nombre de método 'solicitar()'
gracias, ya se me hacía raro
Leyenda!!! gracias por ese dato me tenia confundido como se suponía que funcionaria con nombres de funciones diferentes!! excelente observación.
Estuve rato de entender el codigo del Chain of responsability pattern, porque no le veia sentido de porque se llamaban asi mismo si la variable siguiente es null, e incluso lo corri en vscode y generaba error
pero cuando cambie cuando esta el condicional de si la variable siguiente no es null por el metdo de la otra clase en vez de llamarse asi mismo si me funciono, asi que me imagino que es un error en el ejemplo, podrian verificar
en DescuentoHandler
classDescuentoHandler{constructor(){this.siguiente=null;}solicitarDescuento(solicitud){if(solicitud.tipo==="descuento"){console.log(`Se aplicó un descuento del 10% por un total de ${solicitud.cantidad*0.1}`);}elseif(this.siguiente!==null){this.siguiente.solicitarDescuento(solicitud);}}}
por
classDescuentoHandler{constructor(){this.siguiente=null;}solicitarDescuento(solicitud){if(solicitud.tipo==="descuento"){console.log(`Se aplicó un descuento del 10% por un total de ${solicitud.cantidad*0.1}`);}elseif(this.siguiente!==null){this.siguiente.solicitarEnvioGratis(solicitud);}}}