Patrones de diseño en JavaScript con ejemplos para Node.js
Los patrones de diseño son soluciones probadas para problemas comunes de desarrollo. En JavaScript, especialmente en el entorno Node.js, ayudan a crear código escalable, mantenible y reutilizable. En este artículo analizaremos cuatro patrones principales: Singleton, Factory, Observer y Module, con ejemplos prácticos.
1. Patrón Singleton
Singleton garantiza que una clase tenga solo una instancia y proporciona un punto de acceso global a ella. En Node.js se usa frecuentemente para conexiones a bases de datos o configuración de la aplicación.
Implementación de Singleton en Node.js
class Database { constructor() { if (Database.instance) { return Database.instance; } this.connection = null; Database.instance = this; }
async connect(uri) { // Simulación de conexión a BD this.connection = `Connected to ${uri}`; console.log(this.connection); }
getConnection() { return this.connection; }}
// Usoconst db1 = new Database();const db2 = new Database();
console.log(db1 === db2); // true
db1.connect('mongodb://localhost:27017/myapp');console.log(db2.getConnection()); // "Connected to mongodb://localhost:27017/myapp"Cuándo usarlo: Gestión de pool de conexiones, logger global, sistemas de caché.
2. Patrón Factory
Factory permite crear objetos sin especificar la clase concreta. Centraliza la lógica de creación de objetos, simplificando el mantenimiento del código.
Implementación de Factory para validadores
class EmailValidator { validate(value) { return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value); }}
class PhoneValidator { validate(value) { return /^\\+?[\\d\\s\\-()]{7,15}$/.test(value); }}
class ValidatorFactory { createValidator(type) { switch (type) { case 'email': return new EmailValidator(); case 'phone': return new PhoneValidator(); default: throw new Error('Unknown validator type'); } }}
// Usoconst factory = new ValidatorFactory();const emailValidator = factory.createValidator('email');
console.log(emailValidator.validate('test@example.com')); // trueconsole.log(emailValidator.validate('invalid')); // falseCuándo usarlo: Creación de objetos complejos, trabajo con diferentes formatos de datos (JSON, XML, YAML), generación de componentes de UI.
3. Patrón Observer
Observer crea un mecanismo de suscripción que permite a unos objetos (observadores) seguir los cambios en otro objeto (sujeto). En Node.js este patrón está integrado mediante la clase EventEmitter.
Implementación de Observer con EventEmitter
const EventEmitter = require('events');
class NewsPublisher extends EventEmitter { publishArticle(title) { console.log(`📰 Artículo publicado: ${title}`); this.emit('article', { title, date: new Date() }); }}
class Subscriber { constructor(name) { this.name = name; }
receiveArticle(article) { console.log(`🔔 ${this.name} recibió: "${article.title}"`); }}
// Usoconst publisher = new NewsPublisher();const subscriber1 = new Subscriber('Ana');const subscriber2 = new Subscriber('Iván');
publisher.on('article', (data) => subscriber1.receiveArticle(data));publisher.on('article', (data) => subscriber2.receiveArticle(data));
publisher.publishArticle('Patrones de diseño en JavaScript');// Salida:// 📰 Artículo publicado: Patrones de diseño en JavaScript// 🔔 Ana recibió: "Patrones de diseño en JavaScript"// 🔔 Iván recibió: "Patrones de diseño en JavaScript"Cuándo usarlo