Menu
Coddy logo textTech

Patrón Strategy

Parte de la sección Programación orientada a objetos del Journey de Python de Coddy. Lección 48 de 64.

El patrón Strategy define una familia de algoritmos, encapsula cada uno de ellos y los hace intercambiables. Puedes cambiar de algoritmo en tiempo de ejecución sin modificar el código del cliente.

Aquí tienes clases de estrategia sencillas para diferentes métodos de pago:

class CreditCard:
    def pay(self, amount):
        return f"Paid ${amount} with Credit Card"

class PayPal:
    def pay(self, amount):
        return f"Paid ${amount} with PayPal"

class Bitcoin:
    def pay(self, amount):
        return f"Paid ${amount} with Bitcoin"

Cada estrategia implementa el mismo método (pay), pero con un comportamiento diferente.

Crea una clase de contexto que utilice estrategias:

class ShoppingCart:
    def __init__(self):
        self.total = 0
        self.payment_strategy = None
    
    def add_item(self, price):
        self.total += price
    
    def set_payment_strategy(self, strategy):
        self.payment_strategy = strategy
    
    def checkout(self):
        return self.payment_strategy.pay(self.total)

La clase de contexto puede cambiar entre diferentes estrategias de pago.

Usa el patrón de estrategia:

cart = ShoppingCart()
cart.add_item(50)
cart.add_item(30)

# Usa la estrategia de tarjeta de crédito
cart.set_payment_strategy(CreditCard())
print(cart.checkout())

# Cambia a la estrategia de PayPal
cart.set_payment_strategy(PayPal())
print(cart.checkout())

Crea otro ejemplo con estrategias de ordenación:

class BubbleSort:
    def sort(self, data):
        return f"Bubble sorted: {sorted(data)}"

class QuickSort:
    def sort(self, data):
        return f"Quick sorted: {sorted(data)}"

class Sorter:
    def __init__(self, strategy):
        self.strategy = strategy
    
    def set_strategy(self, strategy):
        self.strategy = strategy
    
    def sort_data(self, data):
        return self.strategy.sort(data)

# Usar diferentes estrategias de ordenamiento
numbers = [3, 1, 4, 1, 5]

sorter = Sorter(BubbleSort())
print(sorter.sort_data(numbers))

sorter.set_strategy(QuickSort())
print(sorter.sort_data(numbers))

Salida:

Paid $80 with Credit Card
Paid $80 with PayPal
Bubble sorted: [1, 1, 3, 4, 5]
Quick sorted: [1, 1, 3, 4, 5]

Punto clave: el patrón Strategy te permite intercambiar algoritmos durante la ejecución. Define distintas estrategias con la misma interfaz y después deja que la clase de contexto elija cuál usar. Esto hace que tu código sea flexible y fácil de ampliar con nuevos algoritmos sin cambiar el código existente.

challenge icon

Desafío

Intermedio

Implementa una nueva estrategia BitcoinPayment para nuestro sistema de compras.

Tu tarea es:

  1. Crea una clase BitcoinPayment que implemente PaymentStrategy
    • Debe aceptar wallet_address en el constructor
    • El método pay debe imprimir exactamente: Paying $X using Bitcoin wallet: Y, donde X es el importe y Y es la dirección de la cartera
    • El método pay debe devolver True después de imprimir
  2. Escribe una función main que:
    • Cree un carrito de compras
    • Añada al carrito un portátil que cueste $1200 y unos auriculares que cuesten $100
    • Cree un BitcoinPayment con la dirección de la cartera "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
    • Establezca esta estrategia de pago en el carrito
    • Llame al método checkout

El código inicial ya incluye if __name__ == "__main__": al final. No necesitas añadirlo tú. Esta es una convención de Python que garantiza que tu función main() solo se ejecute cuando el archivo se ejecuta directamente (no cuando otro módulo lo importa). Simplemente define tu función main() y el bloque proporcionado la llamará automáticamente.

Sigue la misma estructura que se muestra en los ejemplos de la lección.

Pruébalo tú mismo

from abc import ABC, abstractmethod

class PaymentStrategy(ABC):
    @abstractmethod
    def pay(self, amount):
        pass

class CreditCardPayment(PaymentStrategy):
    def __init__(self, card_number, expiry_date, cvv):
        self.card_number = card_number
        self.expiry_date = expiry_date
        self.cvv = cvv
        
    def pay(self, amount):
        print(f"Paying ${amount} using Credit Card: {self.card_number}")
        return True

class PayPalPayment(PaymentStrategy):
    def __init__(self, email, password):
        self.email = email
        self.password = password
        
    def pay(self, amount):
        print(f"Paying ${amount} using PayPal account: {self.email}")
        return True

class ShoppingCart:
    def __init__(self):
        self.items = []
        self.payment_strategy = None
    
    def add_item(self, item, price):
        self.items.append({"item": item, "price": price})
    
    def set_payment_strategy(self, payment_strategy):
        self.payment_strategy = payment_strategy
    
    def checkout(self):
        total = sum(item["price"] for item in self.items)
        if self.payment_strategy:
            return self.payment_strategy.pay(total)
        else:
            raise ValueError("No payment strategy set")

# Create your BitcoinPayment strategy class here


if __name__ == "__main__":
    main()
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

Practica por tu cuenta: Compilador de Python online