El patrón Strategy en 5 minutos: Adiós a los IFs de cálculo

Cuando estás creando una aplicación, es muy común ofrecer distintas formas de hacer una misma cosa: diferentes métodos de pago, formas de calcular un envío o tipos de descuento.

Sin un patrón de diseño, el código suele convertirse en una bola de nieve de condicionales. Hoy vas a aprender a limpiar eso con el patrón Strategy.

1. El problema: Cálculos llenos de condicionales

Imagina que tienes una tienda en línea y debes calcular el costo de envío según la empresa de transporte.

Crea un archivo llamado envios.py en tu terminal:

Python

def calcular_envio(empresa, peso_kg):
    if empresa == "dhl":
        return peso_kg * 10 + 5  # Tarifa base + peso
    elif empresa == "fedex":
        return peso_kg * 8 + 12
    elif empresa == "olva":
        return peso_kg * 5 + 3
    else:
        raise ValueError("Empresa de envío no válida")

# Probamos el cálculo
costo = calcular_envio("dhl", peso_kg=3)
print(f"Costo de envío: ${costo}")

¿Por qué esto es un dolor de cabeza?

Si la tarifa de DHL cambia, si FedEx lanza una promoción, o si quieres agregar 5 empresas más, tienes que entrar a modificar esta misma función gigante. Un error en un elif rompe el cálculo de todas las demás empresas.

2. La solución: El patrón Strategy

La idea del patrón Strategy es muy simple: cada forma de calcular pasa a ser una "estrategia" independiente. Tu programa principal solo ejecuta la estrategia que le asignes.

Reemplaza tu envios.py por este código:

Python

# 1. Definimos las Estrategias (Algoritmos independientes)

class EnvioDHL:
    def calcular(self, peso_kg):
        return peso_kg * 10 + 5

class EnvioFedEx:
    def calcular(self, peso_kg):
        return peso_kg * 8 + 12

class EnvioOlva:
    def calcular(self, peso_kg):
        return peso_kg * 5 + 3


# 2. El Contexto (El carrito o calculadora de la tienda)

class CalculadoraEnvios:
    def __init__(self, estrategia):
        # Asignamos la estrategia seleccionada
        self.estrategia = estrategia

    def obtener_costo(self, peso_kg):
        # Ejecuta la estrategia actual sin importarle cuál sea
        return self.estrategia.calcular(peso_kg)


# 3. Código principal

# El usuario elige enviar por FedEx
servicio = EnvioFedEx()
calculadora = CalculadoraEnvios(servicio)

costo = calculadora.obtener_costo(peso_kg=3)
print(f"📦 Costo con FedEx: ${costo}")

3. ¿Por qué esto cambia las cosas?

  1. Cada regla está aislada: Si DHL cambia sus precios, solo modificas la clase EnvioDHL. Cero riesgo de alterar los precios de FedEx u Olva.
  2. Puedes cambiar de estrategia sobre la marcha:

Python

# Si el cliente cambia de opinión en el carrito:
calculadora.estrategia = EnvioOlva()
print(f"Nuevo costo con Olva: ${calculadora.obtener_costo(3)}")

Tu turno (Reto de 2 minutos)

Imagina que agregas un nuevo servicio de envío rápido en moto llamado EnvioExpress:

  1. Crea la clase EnvioExpress con su método calcular(self, peso_kg) que cobre un monto fijo de $15 sin importar el peso.
  2. Pásaselo a la CalculadoraEnvios y calcula el costo.

¡Y listo! Ya dominas dos de los patrones más usados en la industria.