Skip to main content

Inicia sesión en CleanKata

Sigue tu progreso, gana XP y desbloquea todas las lecciones.

Al iniciar sesión aceptas nuestros Términos de uso y Política de privacidad.

Arquitectura Limpia80 XP8 min

Polimorfismo: El Poder de los Plugins

El polimorfismo permite tratar dependencias externas como plugins intercambiables, haciendo que la lógica central sea independiente del dispositivo.

Por qué importa

Antes de la POO, llamar a una función requería conocer su dirección en tiempo de compilación — o usar un puntero, lo cual era propenso a errores e indisciplinado. La contribución de la POO a la arquitectura no es la encapsulación ni la herencia: es el polimorfismo seguro y disciplinado a través de interfaces. Una interfaz hace que los punteros a funciones sean implícitos, tipados y seguros.

Esto es arquitectónicamente transformador. Cuando dependes de una interfaz en lugar de una clase concreta, la dirección de la dependencia del código fuente se vuelve independiente de la dirección del flujo de control. Puedes apuntar cualquier dependencia a una abstracción e intercambiar implementaciones libremente — convirtiendo los sistemas externos (bases de datos, APIs, frameworks de UI, dispositivos de E/S) en plugins de tu lógica central. El módulo main decide qué plugin cargar. El núcleo nunca lo sabe ni le importa.

✗El problema

Despachar sobre una cadena de tipo con if/elif obliga a que cada nuevo formato de salida edite la misma función. Agregar "slack" o "webhook" significa tocar la lógica central — violando el Principio Abierto/Cerrado.

Bad

class ReportGenerator:
    def send(self, report: dict, output_type: str) -> None:
        if output_type == "pdf":
            print(f"[PDF] {report['title']}")
        elif output_type == "csv":
            print(f"[CSV] {report['title']}")
        elif output_type == "email":
            print(f"[EMAIL] {report['title']}")
        else:
            raise ValueError(f"Unknown: {output_type}")
class ReportGenerator {
  send(report: { title: string }, outputType: string): void {
    if (outputType === "pdf")        console.log(`[PDF] ${report.title}`);
    else if (outputType === "csv")   console.log(`[CSV] ${report.title}`);
    else if (outputType === "email") console.log(`[EMAIL] ${report.title}`);
    else throw new Error(`Unknown: ${outputType}`);
  }
}

✓La solución

An abstract notifier interface makes each output format a plugin. The core generator never changes — only a new class is added when a new format is needed.

Good

from abc import ABC, abstractmethod

class ReportNotifier(ABC):
    @abstractmethod
    def send(self, report: dict) -> None: ...

class PdfNotifier(ReportNotifier):
    def send(self, r): print(f"[PDF] {r['title']}")

class CsvNotifier(ReportNotifier):
    def send(self, r): print(f"[CSV] {r['title']}")

class EmailNotifier(ReportNotifier):
    def send(self, r): print(f"[EMAIL] {r['title']}")

class ReportGenerator:
    def __init__(self, notifier: ReportNotifier):
        self._notifier = notifier

    def send(self, report: dict) -> None:
        self._notifier.send(report)

gen = ReportGenerator(PdfNotifier())
gen.send({"title": "Q1 Sales"})
interface ReportNotifier {
  send(report: { title: string }): void;
}

class PdfNotifier   implements ReportNotifier {
  send(r: { title: string }) { console.log(`[PDF] ${r.title}`); }
}
class CsvNotifier   implements ReportNotifier {
  send(r: { title: string }) { console.log(`[CSV] ${r.title}`); }
}
class EmailNotifier implements ReportNotifier {
  send(r: { title: string }) { console.log(`[EMAIL] ${r.title}`); }
}

class ReportGenerator {
  constructor(private notifier: ReportNotifier) {}
  send(report: { title: string }): void { this.notifier.send(report); }
}

const gen = new ReportGenerator(new PdfNotifier());
gen.send({ title: "Q1 Sales" });

💡Conclusión clave

El superpoder arquitectónico del polimorfismo no es la herencia — es la capacidad de convertir cualquier sistema externo en un plugin intercambiable, dejando la lógica de negocio central permanentemente sin cambios.

🔧 Algunos ejercicios pueden tener errores. Si algo parece incorrecto, usa el botón Feedback (abajo a la derecha) para reportarlo — nos ayuda a corregirlo rápido.

Pista: Cada if/else sobre un tipo es una oportunidad perdida para el polimorfismo.

✗ Tu versión