Back

¿Qué es el principio de inversión de dependencia? Explicado de manera simple

¿Qué es el principio de inversión de dependencia? Explicado de manera simple

El Principio de Inversión de Dependencia (DIP, por sus siglas en inglés) es uno de los cinco principios SOLID del diseño orientado a objetos. Ayuda a crear sistemas flexibles y desacoplados al cambiar la dirección de la dependencia — desde implementaciones concretas hacia contratos abstractos. Este artículo te ayudará a entender el DIP en un lenguaje sencillo, con ejemplos que puedes aplicar de inmediato.

Puntos Clave

  • Los módulos de alto nivel no deben depender de módulos de bajo nivel; ambos deben depender de abstracciones
  • El DIP permite una arquitectura flexible y comprobable
  • Verás cómo aplicar el DIP con ejemplos del mundo real en múltiples lenguajes

La definición oficial

Los módulos de alto nivel no deben depender de módulos de bajo nivel. Ambos deben depender de abstracciones. Las abstracciones no deben depender de los detalles. Los detalles deben depender de las abstracciones.

Analicemos esto:

  • Módulo de alto nivel: contiene lógica de negocio (p. ej., realizar un pedido)
  • Módulo de bajo nivel: maneja tareas específicas (p. ej., enviar un correo electrónico)
  • Abstracción: una interfaz o clase base que define el comportamiento, no la implementación

Una analogía visual

Imagina que tienes un OrderService que envía una notificación por correo electrónico cuando se realiza un pedido.

Sin DIP:

OrderService --> EmailService

OrderService está estrechamente acoplado a EmailService. No puedes cambiarlo o simularlo fácilmente.

Con DIP:

OrderService --> INotificationService <-- EmailService

Ahora ambos módulos dependen de una abstracción (INotificationService).

Un ejemplo de código: sin DIP (TypeScript)

class EmailService {
  send(message: string) {
    console.log(`Sending email: ${message}`);
  }
}

class OrderService {
  constructor(private emailService: EmailService) {}

  placeOrder() {
    this.emailService.send("Order placed");
  }
}

Esto acopla estrechamente OrderService a EmailService.

Refactorizado: con DIP (TypeScript)

interface INotificationService {
  send(message: string): void;
}

class EmailService implements INotificationService {
  send(message: string) {
    console.log(`Sending email: ${message}`);
  }
}

class OrderService {
  constructor(private notifier: INotificationService) {}

  placeOrder() {
    this.notifier.send("Order placed");
  }
}

DIP en Python

from abc import ABC, abstractmethod

class NotificationService(ABC):
    @abstractmethod
    def send(self, message: str):
        pass

class EmailService(NotificationService):
    def send(self, message: str):
        print(f"Sending email: {message}")

class OrderService:
    def __init__(self, notifier: NotificationService):
        self.notifier = notifier

    def place_order(self):
        self.notifier.send("Order placed")

# Uso
service = OrderService(EmailService())
service.place_order()

DIP en Java

interface NotificationService {
    void send(String message);
}

class EmailService implements NotificationService {
    public void send(String message) {
        System.out.println("Sending email: " + message);
    }
}

class OrderService {
    private NotificationService notifier;

    public OrderService(NotificationService notifier) {
        this.notifier = notifier;
    }

    public void placeOrder() {
        notifier.send("Order placed");
    }
}

// Uso
OrderService service = new OrderService(new EmailService());
service.placeOrder();

Por qué el DIP es importante

  • Comprobabilidad: Intercambia dependencias reales con simulaciones o falsificaciones
  • Flexibilidad: Cambia implementaciones sin tocar la lógica de alto nivel
  • Separación de preocupaciones: Cada módulo hace un trabajo y se comunica a través de contratos

Concepto erróneo común: DIP ≠ Inyección de Dependencias

Están relacionados, pero no son lo mismo:

  • DIP trata sobre quién depende de quién (dirección de la dependencia)
  • Inyección de Dependencias es una forma de aplicar DIP — inyectando dependencias en lugar de codificarlas directamente

Cuándo usar DIP

Úsalo cuando:

  • Quieres escribir lógica de negocio que no se preocupe por la implementación subyacente
  • Estás trabajando en una aplicación por capas o modular
  • Estás construyendo para facilitar las pruebas o la extensibilidad

Conclusión

El Principio de Inversión de Dependencia consiste en invertir la dirección habitual de la dependencia — para que las abstracciones, no las implementaciones, definan tu arquitectura. Hace que tu código sea más reutilizable, comprobable y robusto frente a cambios.

Preguntas frecuentes

Es un principio de diseño donde los módulos de alto nivel y los módulos de bajo nivel dependen de abstracciones en lugar de depender unos de otros.

No. DIP es un principio. La Inyección de Dependencias es una técnica para lograr el DIP.

Porque puedes intercambiar dependencias reales por simulaciones o stubs que sigan la misma interfaz.

Las interfaces ayudan en TypeScript, pero en JavaScript puedes usar contratos de forma de objeto y patrones para lograr lo mismo.

Listen to your bugs 🧘, with OpenReplay

See how users use your app and resolve issues fast.
Loved by thousands of developers