Los Design Patterns que Todo Developer Debe Conocer

Los Design Patterns que Todo Developer Debe Conocer
Design patterns para developers

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.