Princípios SOLID - O princípio de inversão de dependência
inversão de independência
Como dito no nosso posts anteriores sobre o assunto (se você ainda não viu, clique aqui e aqui), SOLID é um acrônimo mnemônico que relaciona um tópico de boas práticas de programação a cada letra. A aplicação desses princípios tem por objetivo deixar o projeto mais coeso, reaproveitável e torna a sua manutenção mais simples. Nesse post, vamos falar sobre o princípio de inversão de dependência.
Então, o que princípio é esse?
O princípio de inversão de dependência é muito comumente separado em dois conceitos principais que o definem.
1 – Módulos de alto nível não devem depender dos módulos de baixo nível. Os dois devem ser baseados em abstrações.
2 – Abstrações não devem ser baseadas em detalhes. Detalhes devem ser baseados em abstrações.
Inicialmente pode parecer um pouco estranho pensar na palavra "inversão" presente na nomeação desse conceito. Para entender isso, é importante entender como funcionava o desenvolvimento de software antes da formação desse conceito. Métodos mais tradicionais de software utilizam uma abordagem em que módulos de alto nível dependem de módulos de baixo nível, ou seja, a política de alto nível aplicada à um objeto de baixo nível depende diretamente de como é esse objeto de baixo nível. Vamos ver um exemplo simples de aplicação desseconceito: imagine um botão e uma lâmpada. Utilizando um diagrama para ilustrar como um modelo seria implementado sem o principio de inversão de dependência, o modelo ficaria assim:
Em que o botão ligaria a lâmpada, caso ela esteja desligada, e desligaria a lâmpada, caso ela esteja ligada. Sua implementação seria algo assim:
E por que esse programa não seria adequado? Simples. O seu programa Button somente seria adequado para ligar ou desligar uma lâmpada. Caso o dono do sistema deseje que esse botão seja utilizado para desligar um portão eletrônico, por exemplo, deve ser feitas grandes mudanças no método do Poll do Button para que o botão passe a funcionar onde ele é necessário. Ou seja, um modulo de alto nível (Button) está dependendo de um módulo de baixo nível (Lamp).
Mas então, como seria uma implementação utilizando o principio de inversão de dependência?
Para isso nos deparamos com outro conceito importante quando o assunto é o princípio da inversão de dependência: a divisão em camadas. Para que seja possível e fique clara a aplicação do princípio de inversão de dependência é necessário que mais um camada seja adicionada. Essa camada será responsável pela intermediação do botão com o modulo da lâmpada, deixando o modelo do sistema da seguinte forma:
Com isso, o Button fará uma implementação que vai utilizar o turnOn e turnOff oferecidos pelo ButtonServer, enquanto a Lamp detalhará ao ButtonServer quais os detalhes necessários para que o turnOn e turnOff sejam executados corretamente. Para isso o ButtonServer utiliza o conceito de abstração, ou seja, as funcionalidades turnOn e turnOff apresentadas por ele serão só representativas, abstratas, e somente serão implementadas quando um módulos de baixo nível, ao qual essas funcionalidades são aplicadas, apresentar os detalhes necessárias para a execução.
Dessa forma, voltando ao nosso exemplo, caso seja necessário que o botão também seja utilizado para a abertura de um portão eletrônico, somente será necessário adicionar ao modelo um motor, que representa os detalhes necessários para que as funções turnOn e turnOff direcionadas ao motor do portão sejam executadas. O modelo então fica assim:
Por fim, pode-se observar um isolamento entre a camada de negócios dos detalhes. O comportamento do botão independe completamente de qual objeto ele está ligando ou desligando. Sua lógica de ligar quando está desligado e desligar quando está ligado estará sempre intocada e será aplicada em qualquer um dos casos.
Se quiser saber mais sobre os princípios SOLID, nesse post você aprende sobre o princípio da responsabilidade única e o princípio aberto/ fechado e aqui você vê como funciona o princípio da Substituição de Liskov.