Back

O que é o princípio da inversão de dependência? Explicado de forma simples

O que é o princípio da inversão de dependência? Explicado de forma simples

O Princípio da Inversão de Dependência (DIP) é um dos cinco princípios SOLID de design orientado a objetos. Ele ajuda a criar sistemas flexíveis e desacoplados, alterando a direção da dependência — de implementações concretas para contratos abstratos. Este artigo vai ajudá-lo a entender o DIP em linguagem simples, com exemplos que você pode aplicar imediatamente.

Principais Pontos

  • Módulos de alto nível não devem depender de módulos de baixo nível; ambos devem depender de abstrações
  • O DIP permite uma arquitetura flexível e testável
  • Você verá como aplicar o DIP com exemplos do mundo real em várias linguagens

A definição oficial

Módulos de alto nível não devem depender de módulos de baixo nível. Ambos devem depender de abstrações. Abstrações não devem depender de detalhes. Detalhes devem depender de abstrações.

Vamos decompor isso:

  • Módulo de alto nível: contém lógica de negócios (ex: realizar um pedido)
  • Módulo de baixo nível: lida com tarefas específicas (ex: enviar um email)
  • Abstração: uma interface ou classe base que define comportamento, não implementação

Uma analogia visual

Imagine que você tem um OrderService que envia uma notificação por email quando um pedido é feito.

Sem DIP:

OrderService --> EmailService

OrderService está fortemente acoplado ao EmailService. Você não pode trocá-lo ou simulá-lo facilmente.

Com DIP:

OrderService --> INotificationService <-- EmailService

Agora ambos os módulos dependem de uma abstração (INotificationService).

Um exemplo de código: sem DIP (TypeScript)

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

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

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

Isso acopla fortemente o OrderService ao EmailService.

Refatorado: com 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 em 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 em 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 que o DIP é importante

  • Testabilidade: Troque dependências reais por mocks ou fakes
  • Flexibilidade: Mude implementações sem tocar na lógica de alto nível
  • Separação de preocupações: Cada módulo faz um trabalho e se comunica através de contratos

Equívoco comum: DIP ≠ Injeção de Dependência

Eles estão relacionados, mas não são a mesma coisa:

  • DIP é sobre quem depende de quem (direção da dependência)
  • Injeção de Dependência é uma maneira de aplicar o DIP — injetando dependências em vez de codificá-las diretamente

Quando usar o DIP

Use-o quando:

  • Você quer escrever lógica de negócios que não se preocupa com a implementação subjacente
  • Você está trabalhando em uma aplicação em camadas ou modular
  • Você está construindo para testabilidade ou extensibilidade

Conclusão

O Princípio da Inversão de Dependência trata de inverter a direção usual da dependência — para que abstrações, não implementações, definam sua arquitetura. Isso torna seu código mais reutilizável, testável e robusto a mudanças.

Perguntas Frequentes

É um princípio de design onde módulos de alto nível e módulos de baixo nível dependem de abstrações em vez de dependerem um do outro.

Não. DIP é um princípio. Injeção de Dependência é uma técnica para alcançar o DIP.

Porque você pode trocar dependências reais por mocks ou stubs que seguem a mesma interface.

Interfaces ajudam em TypeScript, mas em JavaScript você pode usar contratos de forma de objeto e padrões para alcançar o mesmo resultado.

Listen to your bugs 🧘, with OpenReplay

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