Los Design Patterns que Todo Developer Debe Conocer

El Caos de Programar Sin Estrategia
Imagina que entras a un proyecto donde cada función, clase y módulo parecen escritos sin un plan claro. No hay coherencia en la estructura del código, las dependencias están entrelazadas de forma confusa y hacer un cambio mínimo puede romper todo el sistema. Este es el resultado de desarrollar sin una estrategia clara.
Los design patterns (patrones de diseño) nacen como una solución a este problema. Son enfoques probados y documentados para resolver problemas comunes en el desarrollo de software, permitiendo escribir código más limpio, mantenible y escalable. No se trata de reglas inflexibles, sino de herramientas que ayudan a los desarrolladores a estructurar mejor sus aplicaciones y evitar el caos del código desordenado.
A continuación, exploraremos cinco de los patrones de diseño más utilizados y cómo pueden mejorar tu flujo de trabajo como developer.
1. Singleton
✨ ¿Qué es?
El patrón Singleton garantiza que una clase tenga una única instancia en toda la aplicación y proporciona un punto global de acceso a ella.
🌟 ¿Cuándo usarlo?
Se usa cuando necesitas que solo haya una instancia de una clase, como en el caso de gestores de configuración, conexiones a bases de datos o registros de logs.
🛠 Ejemplo en JavaScript:
class Singleton {
constructor() {
if (!Singleton.instance) {
Singleton.instance = this;
}
return Singleton.instance;
}
}
const instance1 = new Singleton();
const instance2 = new Singleton();
console.log(instance1 === instance2); // true
2. Factory Method
✨ ¿Qué es?
El patrón Factory Method permite crear objetos sin especificar la clase exacta a la que pertenecen. En su lugar, delega la creación a un método especializado.
🌟 ¿Cuándo usarlo?
Se usa cuando necesitas instanciar diferentes tipos de objetos de forma flexible sin acoplar el código a una implementación específica.
🛠 Ejemplo en JavaScript:
class Car {
constructor(brand) {
this.brand = brand;
}
}
class CarFactory {
static createCar(brand) {
return new Car(brand);
}
}
const myCar = CarFactory.createCar("Toyota");
console.log(myCar.brand); // Toyota
3. Observer
✨ ¿Qué es?
El patrón Observer permite definir una relación de suscriptor-publicador, donde múltiples objetos pueden reaccionar automáticamente a cambios en otro objeto.
🌟 ¿Cuándo usarlo?
Es útil cuando necesitas notificar a múltiples partes sobre cambios en un objeto, como en eventos en interfaces gráficas o patrones de Pub/Sub en arquitecturas backend.
🛠 Ejemplo en JavaScript:
class Observable {
constructor() {
this.observers = [];
}
subscribe(observer) {
this.observers.push(observer);
}
notify(data) {
this.observers.forEach(observer => observer(data));
}
}
const observable = new Observable();
observable.subscribe(data => console.log("Notificado con:", data));
observable.notify("Nuevo evento");
4. Decorator
✨ ¿Qué es?
El patrón Decorator permite agregar funcionalidad a un objeto de manera flexible sin modificar su estructura original.
🌟 ¿Cuándo usarlo?
Es útil cuando necesitas extender el comportamiento de clases sin modificar su código base, como en middlewares de Express.js o wrappers de funcionalidad.
🛠 Ejemplo en JavaScript:
function withLogging(fn) {
return function (...args) {
console.log("Ejecutando función con args:", args);
return fn(...args);
};
}
function sum(a, b) {
return a + b;
}
const sumWithLogging = withLogging(sum);
console.log(sumWithLogging(2, 3)); // Ejecutando función con args: [2,3] \n 5
5. Strategy
✨ ¿Qué es?
El patrón Strategy permite definir una familia de algoritmos intercambiables y delegar su ejecución según sea necesario.
🌟 ¿Cuándo usarlo?
Cuando necesitas cambiar la lógica de un algoritmo sin modificar la estructura del código, como en estrategias de ordenamiento o métodos de pago en e-commerce.
🛠 Ejemplo en JavaScript:
class PaymentStrategy {
pay(amount) {
throw new Error("Método no implementado");
}
}
class PayPal extends PaymentStrategy {
pay(amount) {
console.log(`Pagando $${amount} con PayPal`);
}
}
class CreditCard extends PaymentStrategy {
pay(amount) {
console.log(`Pagando $${amount} con tarjeta de crédito`);
}
}
class PaymentProcessor {
constructor(strategy) {
this.strategy = strategy;
}
executePayment(amount) {
this.strategy.pay(amount);
}
}
const paypal = new PayPal();
const processor = new PaymentProcessor(paypal);
processor.executePayment(100); // Pagando $100 con PayPal
Conclusión
Entender y aplicar patrones de diseño puede marcar la diferencia entre un código caótico y uno estructurado, escalable y fácil de mantener. Estos cinco patrones son solo una introducción al vasto mundo de los design patterns, pero dominarlos te dará una base sólida para escribir mejor código y mejorar tu workflow como developer.