Strategy Pattern con Python y setprocessor

Clase 15 de 27Curso de Patrones de Diseño y SOLID en Python

Resumen

El Strategy Pattern te ayuda a diseñar software flexible y mantenible. Aquí verás cómo intercambiar múltiples algoritmos, modificar la estrategia en tiempo de ejecución y programar contra interfaces usando protocols de Python, con un ejemplo claro aplicado a un servicio de pagos y el método setprocessor en PaymentService.

¿Qué es el Strategy Pattern y por qué importa?

El Strategy es un patrón de diseño de comportamiento que permite definir una familia de algoritmos, encapsularlos y hacerlos intercambiables sin tocar la lógica de alto nivel. La clase de alto nivel depende de una interfaz, no de implementaciones concretas, y cada estrategia concreta implementa esa interfaz. Así, se inyecta la estrategia adecuada al contexto correcto.

  • Intercambio de algoritmos sin modificar el cliente.
  • Cambio de estrategia en tiempo de ejecución con un método dedicado.
  • Bajo acoplamiento al depender de interfaces o protocols.
  • Reutilización de código y mayor legibilidad.

¿Cómo se aplica en un servicio de pagos con Python?

En un flujo de pagos, la clase PaymentService expone un método setprocessor para cambiar la estrategia activa. Se definen tres procesadores como estrategias, todos cumpliendo la misma interfaz. La selección puede venir de una función externa que decide qué estrategia conviene según las condiciones del contexto y la inyecta en el servicio.

¿Cómo definir la interfaz con Protocol?

Usa Protocol para expresar la interfaz esperada por la clase de alto nivel. Así, cualquier implementación que cumpla la firma puede actuar como estrategia.

from typing import Protocol

class PaymentProcessor(Protocol):
    def process(self, amount: float) -> str: ...

class ProcessorOne:
    def process(self, amount: float) -> str:
        return f"Procesado con ProcessorOne: {amount}"

class ProcessorTwo:
    def process(self, amount: float) -> str:
        return f"Procesado con ProcessorTwo: {amount}"

class ProcessorThree:
    def process(self, amount: float) -> str:
        return f"Procesado con ProcessorThree: {amount}"

¿Cómo cambiar la estrategia con setprocessor?

La clase de alto nivel depende solo de la interfaz y ofrece setprocessor para modificar la estrategia en ejecución sin reiniciar ni reescribir lógica.

class PaymentService:
    def __init__(self, processor: PaymentProcessor):
        self._processor = processor

    def setprocessor(self, processor: PaymentProcessor) -> None:
        self._processor = processor

    def pay(self, amount: float) -> str:
        return self._processor.process(amount)

Puedes centralizar la elección en una función externa que retorna la estrategia adecuada según el contexto, y luego inyectarla con setprocessor.

def select_strategy(condicion: str) -> PaymentProcessor:
    if condicion == "opcion1":
        return ProcessorOne()
    if condicion == "opcion2":
        return ProcessorTwo()
    return ProcessorThree()

service = PaymentService(select_strategy("opcion1"))
service.pay(100.0)
service.setprocessor(select_strategy("opcion2"))
service.pay(150.0)

¿Qué habilidades y keywords conviene dominar?

Para aplicarlo con solidez conviene dominar los conceptos y su relación práctica en el código. Esto facilita seleccionar la estrategia correcta y mantener bajo acoplamiento.

  • Strategy Pattern: patrón de diseño de comportamiento para algoritmos intercambiables.
  • Algoritmos intercambiables: varias clases resuelven el mismo problema de formas distintas.
  • Modificación en tiempo de ejecución: cambiar la estrategia mientras el programa corre con setprocessor.
  • Interfaces y protocolos en Python: uso de Protocol para tipar y validar la estrategia.
  • Inyección de estrategia: selección e inyección del procesador en PaymentService.
  • Clases de alto y bajo nivel: alto nivel depende de una interfaz, bajo nivel implementa la interfaz.
  • Selección de estrategia externa: función o clase que decide la estrategia y la inyecta con setprocessor.

¿Has utilizado el Strategy Pattern? Comparte en comentarios cómo lo implementaste y qué decisiones de selección de estrategia te funcionaron mejor.