El patron Strategy

undefined

Descripción

El Strategy Pattern (patrón de estrategia) es un patrón de diseño de software que pertenece a la categoría de los patrones de comportamiento. Este patrón define una familia de algoritmos, encapsula cada uno de ellos y los hace intercambiables. Permite que el algoritmo varíe independientemente de los clientes que lo utilizan.

Componentes del Strategy Pattern

Contexto: Es la clase que utiliza una estrategia. Tiene una referencia a un objeto de tipo Estrategia y lo usa para ejecutar un algoritmo específico.

Estrategia: Es una interfaz o clase abstracta que define un conjunto de métodos que deben implementar todas las estrategias concretas. Puede tener uno o más métodos que representan los algoritmos intercambiables.

Estrategias Concretas: Son implementaciones concretas de la interfaz Estrategia. Cada estrategia concreta implementa el algoritmo definido en la interfaz Estrategia.

Ejemplo de Implementación en JavaScript

Imaginemos un ejemplo donde tenemos una tienda de comercio electrónico que calcula el precio total de una compra según la estrategia de descuento aplicada. Implementaremos el Strategy Pattern para manejar diferentes estrategias de descuento:

// Interfaz Estrategiaclass DiscountStrategy {  applyDiscount(price) {    // Método que debe ser implementado por las estrategias concretas  }}// Estrategia Concreta 1: Descuento del 10%class TenPercentDiscount extends DiscountStrategy {  applyDiscount(price) {    return price * 0.9;  }}// Estrategia Concreta 2: Descuento fijo de $20class FixedDiscount extends DiscountStrategy {  applyDiscount(price) {    return price - 20;  }}// Contexto: Clase que utiliza la estrategiaclass ShoppingCart {  constructor(discountStrategy) {    this.discountStrategy = discountStrategy;    this.items = [];  }  addItem(item) {    this.items.push(item);  }  calculateTotal() {    let totalPrice = this.items.reduce((acc, item) => acc + item.price, 0);    return this.discountStrategy.applyDiscount(totalPrice);  }}// Uso del Strategy Patternlet cart1 = new ShoppingCart(new TenPercentDiscount());cart1.addItem({ name: 'Laptop', price: 1000 });cart1.addItem({ name: 'Mouse', price: 50 });console.log("Total con 10% de descuento:", cart1.calculateTotal());let cart2 = new ShoppingCart(new FixedDiscount());cart2.addItem({ name: 'Phone', price: 500 });console.log("Total con descuento fijo de $20:", cart2.calculateTotal());

Explicación del Código

  • DiscountStrategy: Es la interfaz que define el método applyDiscount() que deben implementar todas las estrategias concretas.
  • TenPercentDiscount y FixedDiscount: Son estrategias concretas que implementan la interfaz DiscountStrategy con algoritmos específicos para aplicar descuentos del 10% y un descuento fijo de $20, respectivamente.
  • ShoppingCart: Es el contexto que utiliza una estrategia de descuento para calcular el precio total de los productos en el carrito. Tiene una referencia a una instancia de DiscountStrategy y utiliza su método applyDiscount() para aplicar el descuento correspondiente al calcular el total.

Ventajas del Strategy Pattern

  • Flexibilidad: Permite cambiar el comportamiento de un objeto en tiempo de ejecución sin alterar el código que lo usa.
  • Reutilización de Código: Facilita la reutilización de algoritmos, ya que las estrategias pueden ser intercambiadas y reutilizadas en diferentes contextos.
  • Desacoplamiento: Separa los algoritmos de la lógica principal del objeto, lo que facilita la modificación y mantenimiento del código.

Consideraciones

  • Elección de Estrategia: Se debe elegir cuidadosamente las estrategias y asegurarse de que cada estrategia tenga una única responsabilidad bien definida.
  • Número de Estrategias: Si hay muchas estrategias diferentes, la gestión de las clases concretas puede volverse compleja.
  • Impacto en el Rendimiento: La selección de estrategias en tiempo de ejecución puede tener un ligero impacto en el rendimiento, aunque este impacto suele ser mínimo y depende del contexto de la aplicación.

Conclusioón

En resumen, el Strategy Pattern es útil cuando se necesita manejar múltiples algoritmos o comportamientos de manera flexible y desacoplada en una aplicación. Proporciona una forma estructurada de definir, utilizar y cambiar comportamientos sin afectar el código existente de manera significativa.