DIP: El Principio de Inversión de Dependencias
Las dependencias del código fuente deben apuntar solo a abstracciones — las Fábricas Abstractas crean la frontera arquitectónica entre el código concreto volátil y la política estable.
Por qué importa
El DIP establece que la política de alto nivel (reglas de negocio) no debe depender del detalle de bajo nivel (bases de datos, frameworks, E/S). Ambos deben depender de abstracciones. En el mundo ideal del DIP, cada dependencia del código fuente apunta hacia una interfaz abstracta, nunca hacia una implementación concreta.
Martin ilustra la consecuencia práctica con el patrón Abstract Factory. El código de negocio necesita crear objetos — un pedido, un repositorio, un pago — pero no debe llamar directamente a new MySQLOrderRepository(), porque eso acoplaría la política de negocio estable a una elección de infraestructura volátil. La Abstract Factory crea objetos concretos al otro lado de una frontera arquitectónica, para que el código de negocio dependa solo de la interfaz de la fábrica y la interfaz del repositorio. La "línea curva" que separa lo abstracto de lo concreto es la frontera arquitectónica misma — todo lo estable y reutilizable de un lado, todo lo volátil y reemplazable del otro.
✗El problema
OrderService directly instantiates MySQLOrderRepository — the business layer is hardwired to a database technology it should never know about.
Bad
class MySQLOrderRepository:
def save(self, order: dict) -> None:
mysql.execute("INSERT INTO orders ...", order)
class OrderService:
def __init__(self):
self.repo = MySQLOrderRepository() # hardwired to MySQL!
def place_order(self, order: dict) -> None:
# business logic...
self.repo.save(order)
class MySQLOrderRepository {
save(order: Order): void {
mysql.execute("INSERT INTO orders ...", order);
}
}
class OrderService {
private repo = new MySQLOrderRepository(); // hardwired — DIP violation
placeOrder(order: Order): void {
// business logic...
this.repo.save(order);
}
}
✓La solución
OrderService depends only on an abstract repository interface. An Abstract Factory creates the concrete implementation — business policy and infrastructure detail are separated by an architectural boundary.
Good
from abc import ABC, abstractmethod
class OrderRepositoryInterface(ABC):
@abstractmethod
def save(self, order: dict) -> None: ...
class OrderRepositoryFactory(ABC):
@abstractmethod
def create(self) -> OrderRepositoryInterface: ...
# ── Stable policy (business side) ────────────────────────────────────────────
class OrderService:
def __init__(self, factory: OrderRepositoryFactory):
self.repo = factory.create() # depends on abstraction only
def place_order(self, order: dict) -> None:
# business logic...
self.repo.save(order)
# ── Volatile detail (infrastructure side) ────────────────────────────────────
class MySQLOrderRepository(OrderRepositoryInterface):
def save(self, order: dict) -> None:
mysql.execute("INSERT INTO orders ...", order)
class MySQLRepositoryFactory(OrderRepositoryFactory):
def create(self) -> OrderRepositoryInterface:
return MySQLOrderRepository()
interface OrderRepository {
save(order: Order): void;
}
interface OrderRepositoryFactory {
create(): OrderRepository;
}
// ── Stable policy (business side) ────────────────────────────────────────────
class OrderService {
private repo: OrderRepository;
constructor(factory: OrderRepositoryFactory) {
this.repo = factory.create(); // depends on abstraction
}
placeOrder(order: Order): void {
// business logic...
this.repo.save(order);
}
}
// ── Volatile detail (infrastructure side) ────────────────────────────────────
class MySQLOrderRepository implements OrderRepository {
save(order: Order): void {
mysql.execute("INSERT INTO orders ...", order);
}
}
class MySQLRepositoryFactory implements OrderRepositoryFactory {
create(): OrderRepository { return new MySQLOrderRepository(); }
}
💡Conclusión clave
Cada new ClaseConncreta() dentro de tu lógica de negocio es una violación del DIP — conecta rígidamente la política estable a un detalle volátil. Usa una fábrica o inyecta la dependencia para que la capa de negocio nunca sepa con qué tipo concreto está trabajando.
🔧 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 `new ClaseConcreta()` en tu lógica de negocio es una violación del DIP — usa una fábrica o inyecta la dependencia.
✗ Tu versión