SOLID — Dependency Inversion Principle (DIP)

Vinicius Sanchez
4 min readMay 4, 2021

--

Pra mim, um dos princípios mais legais e também o último da nossa série de artigos sobre SOLID, hoje vamos conhecer um pouco mais sobre o DIP (Dependency Inversion Principle ou em português, Princípio da Inversão de Dependência). Na teoria ele é bem simples, basicamente nos diz que devemos sempre depender de abstrações e não de implementações.

Em suas escritas, Uncle Bob diz que este princípio pode ser definido da seguinte forma:

1. Módulos de alto nível não devem depender de módulos de baixo nível. Ambos devem depender da abstração.

2. Abstrações não devem depender de detalhes. Detalhes devem depender de abstrações.

Inversão de Dependência x Injeção de Dependência

Ao trabalhar com a programação orientada a objetos, é muito comum ouvirmos o termo “Injeção de Dependência”. Você mesmo deve estar se perguntando qual a diferença entre eles. Vale ressaltar que, ambos são coisas distintas, mas que relacionam entre si com um proposito em comum: deixar o código desacoplado e de fácil manutenção.

Nota: Inversão de dependência, é um princípio (conceito) e a Injeção de dependência é um padrão de projeto (Design Pattern).

Vamos entender tudo isso na prática através de alguns exemplos:

Se você estiver lembrado, no artigo anterior onde nos aprendemos sobre o Interface Segregation Principle, criamos um projeto fictício para cadastro de aves em um determinado zoológico. Dando sequência a este projeto, vamos agora pensar na sua principal função, que é de fato, efetuar o cadastro de aves.

Uma premissa para que o cadastro seja efetuado, é estabelecer uma conexão com um banco de dados, por tanto, o método Salvar vai criar uma instância da classe TFirebirdConnection para realizar as operações.

Se você acompanhou todos os artigos da série sobre SOLID até o momento, acredito que você já tenha percebido que nesse pequeno trecho de código temos um alto nível de acoplamento. Isso acontece porque a classe TPinguim tem a responsabilidade de criar uma instância da classe TFirebirdConnection. Se quiséssemos reaproveitar essa classe em outro sistema, teríamos que obrigatoriamente levar a classe TFirebirdConnection junto, portanto, temos um forte acoplamento aqui. Para resolver esse problema, podemos refatorar nosso código da seguinte forma:

Com o código refatorado, a criação do objeto TFirebirdConnection deixa de ser uma responsabilidade da classe TPinguim. A classe de conexão com o banco de dados virou uma dependência que deve ser injetada no método Salvar. Isso mesmo, injetada. Nesta pequena refatoração, aplicamos o padrão de projeto de Injeção de dependência.

Apesar de termos usado a injeção de dependência para melhorar o nível de acoplamento do nosso código, ele continua violando o princípio da inversão de dependência (lembre-se, um não é igual ao outro).

Além de violar o DIP, se você prestar atenção na forma que o exemplo foi codificado irá perceber que ele também viola o Open-Closed Principle. Por exemplo, se precisarmos alterar o banco de dados de Firebird para Postgres teríamos que editar a classe TPinguim.

Aplicando o DIP

Você deve estar se perguntando porque que ainda nosso projeto viola o princípio da inversão de dependência. A resposta é porque ainda estamos dependendo de uma implementação e não de uma abstração, simples assim.

Assim como nós já vimos, a definição do DIP diz que, um módulo de alto nível não deve depender de módulos de baixo nível, ambos devem depender da abstração. Então, a primeira coisa que precisamos fazer é identificar no nosso código qual é o módulo de alto nível e qual é o módulo de baixo nível. Módulo de alto nível é um módulo que depende de outros módulos.

No nosso exemplo, TPinguim depende da classe TFirebirdConnection. Sendo assim, TPinguim é o módulo de alto nível e TFirebirdConnection é o módulo de baixo nível. Acontece que, TFirebirdConnection é uma implementação e não uma abstração.

Refatorando a classe TFirebirdConnection:

É muito comum você achar em cursos e livros de orientação a objetos, menções orientando para que você “programe para uma interface e não para uma implementação”. Pois bem, é exatamente o que iremos fazer agora, criar uma interface para a nossa classe TFirebirdConnection.

Pronto! Agora a nossa classe TPinguim não tem a mínima ideia de qual banco de dados que a aplicação irá utilizar. Dessa forma, não estamos mais violando o princípio de inversão de dependência e ambas as classes estão desacopladas, dependendo apenas de uma abstração. Além disso, estamos permitindo a reusabilidade do código e também respeitando o SRP e o OCP.

Refletir

Você soldaria uma lâmpada diretamente a fiação elétrica de uma parede?

--

--

Vinicius Sanchez
Vinicius Sanchez

Written by Vinicius Sanchez

Embarcadero MVP | Certified Delphi Developer | SFC | SFPC | KIKF | Graduated in Information Systems and Studying Software Architecture

No responses yet