Menu
Coddy logo textTech

Patrón Strategy

Parte de la sección Programación Orientada a Objetos del Journey de C# de Coddy — lección 55 de 70.

El patrón Strategy es un patrón de comportamiento que te permite definir una familia de algoritmos, encapsular cada uno en su propia clase y hacerlos intercambiables en tiempo de ejecución. En lugar de definir el comportamiento de forma rígida (hardcoding), inyectas la estrategia deseada en un objeto.

El patrón consta de tres partes: una interfaz de estrategia que define el contrato del algoritmo, clases de estrategia concretas que implementan diferentes comportamientos y una clase de contexto que utiliza una estrategia:

public interface IPaymentStrategy
{
    void Pay(decimal amount);
}

public class CreditCardPayment : IPaymentStrategy
{
    public void Pay(decimal amount) => 
        Console.WriteLine($"Paid {amount} via Credit Card");
}

public class PayPalPayment : IPaymentStrategy
{
    public void Pay(decimal amount) => 
        Console.WriteLine($"Paid {amount} via PayPal");
}

public class ShoppingCart
{
    private IPaymentStrategy _paymentStrategy;
    
    public void SetPaymentMethod(IPaymentStrategy strategy)
    {
        _paymentStrategy = strategy;
    }
    
    public void Checkout(decimal total)
    {
        _paymentStrategy.Pay(total);
    }
}

El contexto (ShoppingCart) no sabe qué método de pago está utilizando; simplemente llama a Pay() en cualquier estrategia que se haya proporcionado:

var cart = new ShoppingCart();

cart.SetPaymentMethod(new CreditCardPayment());
cart.Checkout(99.99m);  // Pagado 99.99 vía Tarjeta de Crédito

cart.SetPaymentMethod(new PayPalPayment());
cart.Checkout(49.99m);  // Pagado 49.99 vía PayPal

El patrón Strategy elimina la lógica condicional compleja. Agregar un nuevo método de pago significa crear una nueva clase que implemente IPaymentStrategy - no se necesitan cambios en ShoppingCart. Esto hace que su código esté abierto a la extensión pero cerrado a la modificación.

challenge icon

Desafío

Fácil

Vamos a construir una calculadora de costos de envío utilizando el patrón Strategy. Los diferentes métodos de envío tienen diferentes algoritmos de precios, y su sistema debe permitir cambiar entre ellos en tiempo de ejecución sin cambiar la lógica central de procesamiento de pedidos.

Organizará su código en tres archivos:

  • ShippingStrategy.cs: Defina una interfaz IShippingStrategy en el espacio de nombres Shipping con un método CalculateCost(double weight) que devuelva un double. Luego cree tres clases de estrategia concretas:
    • StandardShipping - calcula el costo como weight * 1.5
    • ExpressShipping - calcula el costo como weight * 3.0 + 5.0 (incluye una tarifa plana express)
    • OvernightShipping - calcula el costo como weight * 5.0 + 10.0 (servicio premium con una tarifa base más alta)
  • OrderProcessor.cs: Cree una clase OrderProcessor en el mismo espacio de nombres. Esta es su clase de contexto que utiliza una estrategia de envío. Debe tener:
    • Un campo privado para mantener la IShippingStrategy actual
    • Un método SetShippingMethod(IShippingStrategy strategy) para cambiar la estrategia de envío
    • Un método ProcessOrder(double weight) que utilice la estrategia actual para calcular y devolver el costo de envío
  • Program.cs: Reúna todo creando un OrderProcessor y demostrando cómo puede intercambiar estrategias de envío en tiempo de ejecución. El mismo procesador puede calcular costos utilizando diferentes algoritmos simplemente cambiando su estrategia.

Recibirá dos entradas:

  • El tipo de método de envío: standard, express, o overnight
  • El peso del paquete como un número decimal (por ejemplo, 4.5)

Cree un OrderProcessor, establezca la estrategia de envío adecuada según el tipo de entrada, luego procese el pedido e imprima el costo calculado.

Por ejemplo, si las entradas son express y 4.5, la salida debería ser:

18.5

Esto demuestra el poder del patrón Strategy: su OrderProcessor no contiene ninguna lógica de cálculo de envío por sí mismo. Simplemente delega en cualquier estrategia que se le haya asignado, lo que facilita la adición de nuevos métodos de envío (como DroneDelivery) ¡sin modificar el procesador en absoluto!

Hoja de referencia

El patrón Strategy es un patrón de comportamiento que define una familia de algoritmos, encapsula cada uno en su propia clase y los hace intercambiables en tiempo de ejecución.

El patrón consta de tres partes:

  • Interfaz Strategy: define el contrato del algoritmo
  • Clases de estrategia concreta: implementan diferentes comportamientos
  • Clase Contexto: utiliza una estrategia sin conocer sus detalles de implementación

Estructura de ejemplo:

// Interfaz Strategy
public interface IPaymentStrategy
{
    void Pay(decimal amount);
}

// Estrategias concretas
public class CreditCardPayment : IPaymentStrategy
{
    public void Pay(decimal amount) => 
        Console.WriteLine($"Paid {amount} via Credit Card");
}

public class PayPalPayment : IPaymentStrategy
{
    public void Pay(decimal amount) => 
        Console.WriteLine($"Paid {amount} via PayPal");
}

// Clase Contexto
public class ShoppingCart
{
    private IPaymentStrategy _paymentStrategy;
    
    public void SetPaymentMethod(IPaymentStrategy strategy)
    {
        _paymentStrategy = strategy;
    }
    
    public void Checkout(decimal total)
    {
        _paymentStrategy.Pay(total);
    }
}

Uso - cambiar estrategias en tiempo de ejecución:

var cart = new ShoppingCart();

cart.SetPaymentMethod(new CreditCardPayment());
cart.Checkout(99.99m);  // Pagado 99.99 vía Credit Card

cart.SetPaymentMethod(new PayPalPayment());
cart.Checkout(49.99m);  // Pagado 49.99 vía PayPal

Beneficios:

  • Elimina la lógica condicional compleja
  • Abierto a la extensión, cerrado a la modificación
  • Agregar nuevas estrategias solo requiere crear nuevas clases, sin cambios en el código existente

Pruébalo tú mismo

using System;
using Shipping;

class Program
{
    public static void Main(string[] args)
    {
        // Leer la entrada
        string shippingType = Console.ReadLine();
        double weight = Convert.ToDouble(Console.ReadLine());

        // TODO: Crear una instancia de OrderProcessor

        // TODO: Basado en shippingType ("standard", "express", o "overnight"),
        // crear la estrategia de envío apropiada y establecerla en el procesador

        // TODO: Procesar el pedido e imprimir el costo calculado
    }
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos