Princípio da inversão de dependências - Dependency Inversion Principle

Ao ser aplicado permite que os detalhes passem a depender de abstrações, respeitando a direção da regra de dependências.

Categoria de Programação

Postado em 27 abril 2022

Atualizado em 07 junho 2023

Palavras-chave: dip,solid,principle,princípios,dependecy,inversion,programming

Visualizações: 2064

A regra de dependências diz que os detalhes devem depender das abstrações. Na arquitetura limpa, essa é a regra básica. Módulos de nível alto não devem saber sobre módulos de nível baixo. Se uma classe sabe sobre outra, ela passa a depender dela. Depender de uma classe significa sofrer influência dessa classe. Na arquitetura limpa, as regras de negócio (abstrações) não devem sofrer influência de detalhes (implementações).

Porém, pode ser difícil obedecer a regra de dependências. Em certas ocasiões, as regras de negócio precisam saber sobre os detalhes. O princípio de inversão de dependências (Dependency Inversion Principle) pode ser aplicado para mudar a direção das dependências e fazer com que a regra de dependência seja obedecida.

O que é o princípio de inversão de dependências (DIP)?

O princípio de inversão de dependências é o quinto princípios dos princípios SOLID. Esse princípio diz que a regra de dependências deve ser respeitada. Ou seja:

Os detalhes devem depender de abstrações

Esse princípio também diz que módulos de nível baixo devem depender de módulos de nível alto e nunca ao contrário. As abstrações se referem a interfaces e classes abstratas. Pelo fato das abstrações possuirem apenas uma estrutura de métodos não implementados, o comportamento desses métodos podem ser modificados na implementação. Classes que implementam a mesma abstração podem ser substituídas facilmente.

interface Abstracao {
    void abstractMethod();
}

class ClasseA implements Abstracao {
	public void abstractMethod() {
		// Implementa um tipo de comportamento
	}
}

class ClasseB implements Abstracao {
	public void abstractMethod() {
		// Implementa outro tipo de comportamento
	}
}

As classes que usam o método abstractMethod() não sabem sobre os detalhes da implementação, apenas sabem que elas podem usar o método pré-definido.

class ClasseC {
    Abstracao abstracao;
    
    public ClasseC(Abstracao abstracao) {
	    this.abstracao = abstracao;
    }
	
	public void usarAbstracao() {
		this.abstracao.abstractMethod();
	}
}

A classeC acima, definiu a abstração como parâmetro. Ela não se importa se uma instância da classe B ou C estão sendo passadas desde que as classes implementem a interface “abstracao”. Nesse caso, podemos afirmar que a classeC depende de abstrações.

exemplo de princípio de inversão de dependências

O exemplo acima já está usando o DIP. Por isso, o módulo de nível baixo aponta para o módulo de nível alto e os detalhes dependem da abstração. Perceba que a classeC pode usar o método que os detalhes implementam de modo indireto. Além disso, a classeC não sabe nada sobre os detalhes, respeitando a regra de dependências.

Como usar o princípio de inversão de dependências (DIP)?

O princípio de inversão de dependências só tem um objetivo: inverter as dependências. Aplicamos o DIP quando as dependências não estão respeitando a regra de dependências.

exemplo de violação do princípio de inversão de dependências

O diagrama acima mostra um exemplo de violação de DIP. O módulo de nível alto não deve saber sobre o módulo de nível baixo. Em outras palavras, a classeAA não deve usar a classeZZ.

A regra de dependências diz que módulo de nível baixo devem apontar (depender) para módulos de nível baixo. A violação acima pode ser resolvida com a adição de uma abstração.

exemplo de como resolver uma violação do princípio de inversão de dependências

Aplicando o DIP, as dependências agora apontam para as abstrações.

Por que usar o princípio de inversão de dependências (DIP)?

A principal vantagem ao aplicar o princípio de inversão de dependências é a reutilização. No exemplo acima, quando o DIP era violado, dificilmente a classe ZZ poderia ser substituída por outra sem afetar o módulo de nível alto. Na realidade, existiria uma cadeia de dependências transitivas que usam a classe ZZ, o que tornaria essa substituição mais difícil ainda. Outra grande desvantagem dessa violação é que ela viola outro princípio, o princípio aberto fechado.

Ao resolver a violação acima usando o DIP, as classes que implementam a abstração podem ser substituídas por outras classes que implementam a mesma abstração sem afetar o módulo de nível alto. A classe que pertence ao módulo de nível alto não sabe nada sobre os detalhes que pertencem ao módulo de nível baixo. Além de proteger o módulo de nível alto, esse princípio ajuda na manutenção e possibilita a aplicação do princípio aberto fechado de modo automático.

Conclusão

O princípio de inversão de dependências inverte as dependências para que elas possam obedecer a regra das dependências. Na arquitetura limpa, os detalhes devem apontar para as abstrações para possibilitar a aplicação do princípio aberto fechado, possibilitar a reutilização e melhorar a manutenção.

Projetos práticos

Tutorial de programação do jogo da serpente em javascript

Programando o clássico jogo da serpente usando o framework p5.js. Tutorial indicado para iniciantes da programação que querem aprender os conceitos básico da área criando jogos.

Desenvolvendo o campo de visão de um personagem em um plano 2D

Detectando objetos que entram dentro do campo de visão do personagem. Útil para servir de "gatilho" para eventos em um jogo.

Desenvolvendo um jogo de quebra blocos em javascript

Programando um jogo clássico de arcade usando javascript e p5.js. O usuário deve quebrar os blocos utilizando uma bola ao mesmo tempo que evita que a bola saia pela parte inferior da tela

Implementando um algoritmo de pathfinding

Implementando um programa que encontra a menor distância entre dois pontos dentro de um labirinto usando o algoritmo A* (a-estrela).

Criando um sistema de mini garagem automatizada integrada com um sistema de monitoramento independente

Desenvolvimento de um sistema de monitoramento que exibi todos os eventos que acontecem na garagem automatizada, como abertura de portões ou ocupação de vagas.

Veja também

A comunicação entre dispositivos existe graças aos protocolos

Alguns desses protocolos é o HTTP que usamos em nossos navegadores. Sem esses protocolos teríamos alguns problemas na comunicação de dispositivos através da internet.

Afinal, para que servem os cookies que sempre são solicitados quando entramos em uma página?

A política de privacidade é obrigatória para qualquer site que utiliza dados pessoais do usuário. Porém, quais dados são esses especificamente?

Princípio de segregação de interfaces - Interface Segregation Principle

Os clientes não devem ser forçados a importar métodos que eles não usam. Os métodos devem ser segregados de modo abstrato em interfaces.

Princípio aberto fechado - Open-Closed Principle

O código deve estar aberto para extensões e fechado para modificações. Podemos mudar o comportamento de uma classe adicionando mais código.

Princípio da responsabilidade única - Single Responsibility Principle

Princípio que diz que um módulo só deve mudar por um único motivo. Esse motivo pode ser o conteúdo de um módulo ou os atores que dependem dele.

Algoritmo

O algoritmo é um conjunto de instruções escritas por um programador com intuito de solucionar um problema ou obter um resultado previsto.