- Patrones de Diseño en JavaScript
Los patrones de diseño son soluciones comunes a problemas comunes en el desarrollo de software. En JavaScript, hay una gran variedad de patrones de diseño disponibles, desde patrones de creación hasta patrones de arquitectura.
Ver índice del contenido
11.1 Patrones de creación (Constructor, Módulo, Singleton)
Los patrones de creación son patrones que se utilizan para crear objetos de una manera específica. En JavaScript, algunos de los patrones de creación más comunes son el patrón Constructor, el patrón Módulo y el patrón Singleton.
Ejemplo:
// Constructor function Persona(nombre, edad) { this.nombre = nombre; this.edad = edad; } const persona1 = new Persona("Juan", 30); const persona2 = new Persona("María", 25); // Módulo const miModulo = (() => { const variablePrivada = "Esto es privado"; const funcionPrivada = () => { console.log(variablePrivada); }; const funcionPublica = () => { console.log("Esto es público"); }; return { funcionPublica }; })(); miModulo.funcionPublica(); // Singleton const miSingleton = (() => { let instancia; const crearInstancia = () => { const objeto = new Object("Esto es un singleton"); return objeto; }; return { obtenerInstancia: () => { if (!instancia) { instancia = crearInstancia(); } return instancia; } }; })(); const instancia1 = miSingleton.obtenerInstancia(); const instancia2 = miSingleton.obtenerInstancia(); console.log(instancia1 === instancia2); // true
11.2 Patrones de comportamiento (Observador, Iterador, Estrategia)
Los patrones de comportamiento son patrones que se utilizan para definir la interacción entre objetos y la forma en que responden a cambios en el estado del sistema. En JavaScript, algunos de los patrones de comportamiento más comunes son el patrón Observador, el patrón Iterador y el patrón Estrategia.
Ejemplo:
// Observador const observable = (() => { const suscriptores = []; const suscribirse = fn => suscriptores.push(fn); const notificar = valor => suscriptores.forEach(fn => fn(valor)); return { suscribirse, notificar }; })(); observable.suscribirse(valor => console.log(`Suscriptor 1: ${valor}`)); observable.suscribirse(valor => console.log(`Suscriptor 2: ${valor}`)); observable.notificar("Esto es un mensaje"); // Iterador const iterable = (() => { const arreglo = [1, 2, 3, 4, 5]; const iterator = { indice: 0, siguiente: () => { if (iterator.indice < arreglo.length) { const valor = arreglo[iterator.indice]; iterator.indice++; return { value: valor, done: false }; } else { return { done: true }; } } }; return { [Symbol.iterator]: () => iterator }; })(); for (const valor of iterable) { console.log(valor); } // Estrategia const estrategia = (() => { const estrategias = { sumar: (a, b) => a + b, restar: (a, b) => a - b, multiplicar: (a, b) => a * b }; const ejecutar = (estrategia, a, b) => estrategias[estrategia](a, b); return { ejecutar }; })(); console.log(estrategia.ejecutar("sumar", 1, 2)); // 3 console.log(estrategia.ejecutar("restar", 1, 2)); // -1 console.log(estrategia.ejecutar("multiplicar", 1, 2)); // 2
11.3 Patrones estructurales (Fachada, Decorador, Adaptador)
Los patrones estructurales son patrones que se utilizan para definir la forma en que los objetos se relacionan entre sí y cómo se componen para formar estructuras más grandes. En JavaScript, algunos de los patrones estructurales más comunes son el patrón Fachada, el patrón Decorador y el patrón Adaptador.
Ejemplo:
// Fachada const fachada = (() => { const complejoSistema1 = new ComplejoSistema1(); const complejoSistema2 = new ComplejoSistema2(); const operacionCompleja = () => { complejoSistema1.operacion1(); complejoSistema2.operacion2(); complejoSistema1.operacion3(); }; return { operacionCompleja }; })(); fachada.operacionCompleja(); // Decorador const decorador = (() => { class Componente { constructor() { this.elemento = document.createElement("div"); } dibujar() { this.elemento.innerHTML = "Esto es un componente"; return this.elemento; } } class Decorador1 extends Componente { dibujar() { this.elemento.classList.add("decorador1"); super.dibujar(); } } class Decorador2 extends Componente { dibujar() { this.elemento.classList.add("decorador2"); super.dibujar(); } } const componente = new Decorador1(); const componenteDecorado = new Decorador2(componente); document.body.appendChild(componenteDecorado.dibujar()); })(); // Adaptador const adaptador = (() => { class APIExterna { obtenerDatos() { return "Esto es un dato de la API externa"; } } class AdaptadorAPIExterna { constructor() { this.apiExterna = new APIExterna(); } obtenerDatosAdaptados() { const datos = this.apiExterna.obtenerDatos(); return `Datos adaptados: ${datos}`; } } const adaptador = new AdaptadorAPIExterna(); console.log(adaptador.obtenerDatosAdaptados()); })();
11.4 Patrones de arquitectura (MVC, MVVM, Flux)
Los patrones de arquitectura son patrones que se utilizan para definir la estructura y el flujo de datos de una aplicación. En JavaScript, algunos de los patrones de arquitectura más comunes son el patrón MVC (Modelo-Vista-Controlador), el patrón MVVM (Modelo-Vista-VistaModelo) y el patrón Flux.
Ejemplo:
// MVC const mvc = (() => { class Modelo { constructor() { this.datos = "Esto es un dato del modelo"; } obtenerDatos() { return this.datos; } } class Vista { constructor() { this.elemento = document.createElement("div"); } dibujar(datos) { this.elemento.innerHTML = datos; return this.elemento; } } class Controlador { constructor(modelo, vista) { this.modelo = modelo; this.vista = vista; } iniciar() { const datos = this.modelo.obtenerDatos(); const elemento = this.vista.dibujar(datos); document.body.appendChild(elemento); } } const modelo = new Modelo(); const vista = new Vista(); const controlador = new Controlador(modelo, vista); controlador.iniciar(); })(); // MVVM const mvvm = (() => { class VistaModelo { constructor() { this.datos = "Esto es un dato del vistaModelo"; } obtenerDatos() { return this.datos; } } class Vista { constructor() { this.elemento = document.createElement("div"); this.enlazar(new VistaModelo()); } enlazar(vistaModelo) { this.vistaModelo = vistaModelo; this.actualizar(); } actualizar() { const datos = this.vistaModelo.obtenerDatos(); this.elemento.innerHTML = datos; } } const vista = new Vista(); document.body.appendChild(vista.elemento); })(); // Flux const flux = (() => { const tienda = (() => { let datos = "Esto es un dato de la tienda"; const obtenerDatos = () => datos; const actualizarDatos = nuevoDato => { datos = nuevoDato; }; return { obtenerDatos, actualizarDatos }; })(); const acciones = { actualizarDatos: nuevoDato => tienda.actualizarDatos(nuevoDato) }; const vista = (() => { const elemento = document.createElement("div"); const actualizar = () => { const datos = tienda.obtenerDatos(); elemento.innerHTML = datos; }; tienda.suscribirse(actualizar); return elemento; })(); acciones.actualizarDatos("Esto es un nuevo dato"); document.body.appendChild(vista); })();
11.5 Ejemplos y casos de uso
Algunos ejemplos y casos de uso de los patrones de diseño en JavaScript incluyen:
- Utilizar el patrón Constructor para crear objetos con propiedades y métodos específicos.
- Utilizar el patrón Módulo para encapsular código y exponer solo las funcionalidades necesarias.
- Utilizar el patrón Singleton para garantizar que solo haya una instancia de un objeto en la aplicación.
- Utilizar el patrón Observador para notificar a múltiples objetos cuando ocurre un evento.
- Utilizar el patrón Iterador para recorrer una colección de objetos de manera secuencial.
- Utilizar el patrón Estrategia para definir diferentes algoritmos y seleccionar el más adecuado en tiempo de ejecución.
- Utilizar el patrón Fachada para simplificar la interacción con sistemas complejos.
- Utilizar el patrón Decorador para agregar funcionalidades adicionales a objetos de manera dinámica.
- Utilizar el patrón Adaptador para adaptar la interfaz de un objeto a la interfaz esperada por la aplicación.
- Utilizar el patrón MVC para separar la lógica de negocio, la interfaz de usuario y el controlador en una aplicación.
- Utilizar el patrón MVVM para separar la lógica de negocio y la interfaz de usuario mediante un vistaModelo.
- Utilizar el patrón Flux para manejar el flujo de datos unidireccional en una aplicación.