Chegamos, enfim, ao último post da série sobre os cinco princípios SOLID, o qual abordará o Princípio da Inversão de Dependência (Dependency Inversion Principle), ou simplesmente DIP.
O DIP é base para um bom design orientado a objetos e extremamente importante para o projeto de uma arquitetura de software flexível e focada no domínio.
DEFINIÇÃO
O DIP diz que:
– 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.
Inverter a dependência faz com que um cliente não fique frágil a mudanças relacionadas a detalhes de implementação. Isto é, alterar o detalhe não quebra o cliente. Além disso, o mesmo cliente pode ser reutilizado com outro detalhe de implementação.
Vamos deixar isso mais claro com exemplos.
EXEMPLO DE VIOLAÇÃO
Vejam o clássico exemplo do botão e da lâmpada, onde ambas as classes Botao e Lampada são classes concretas:
public class Botao { private Lampada _lampada; public void Acionar() { if (condicao) _lampada.Ligar(); } }
O design acima viola o DIP uma vez que Botao depende de uma classe concreta Lampada. Ou seja, Botao conhece detalhes de implementação ao invés de termos identificado uma abstração para o design.
Que abstração seria essa? Botao deve ser capaz de tratar alguma ação e ligar ou desligar algum dispositivo, seja ele qual for: uma lâmpada, um motor, um alarme, etc.
INVERTENDO A DEPENDÊNCIA
A solução abaixo inverte a dependência de botão para a lâmpada, fazendo com que ambos agora dependam da abstração Dispositivo:
public class Botao { private Dispositivo _dispositivo; public void Acionar() { if (condicao) _dispositivo.Ligar(); } } public interface Dispositivo { void Ligar(); void Desligar(); } public class Lampada : Dispositivo { public void Ligar() { // ligar lampada } public void Desligar() { // desligar lampada } }
Ilustrando com UML, o que antes era:
Passa a ser:
DIP E ARQUITETURA DE SOFTWARE
O Princípio da Inversão de Dependência é um dos pilares para uma boa arquitetura de software, focada na resolução do problema e flexível quanto a detalhes de implementação, como bancos de dados, serviços web, leitura/escrita de arquivos, etc.
Este princípio reforça que a abstração está mais relacionada ao seu cliente do que ao servidor (a classe que realiza a abstração). No exemplo ilustrado acima, Dispositivo (a abstração) está diretamente ligado ao cliente (Botao). Sua implementação (Lampada) é um mero detalhe.
Sendo assim, Dispositivo ficaria no mesmo pacote (ou componente) do Botao e não junto com sua implementação Lampada. (Esta separação de interface e implementação em componentes distintos é um padrão conhecido por Separated Interface, como catalogado no livro PoEAA, do Martin Fowler.)
Outro exemplo bem comum deste padrão está no uso do padrão Repositório. Neste caso, aplicamos o DIP para que nosso domínio dependa de uma abstração do Repositório, ficando totalmente isolado de detalhes sobre persistência:
Levando a interface para junto do cliente, estamos dizendo “o cliente funciona dessa maneira” e quem implementa a interface (em outro componente) é que deve atender a essa exigência. Ou seja, a interface só mudará por necessidade DO CLIENTE.
Por fim, quando há vários clientes em componentes distintos para a mesma interface, esta fica em um componente a parte. Voltando ao exemplo do Botao, ao colocar Dispositivo em um componente próprio (nem com o cliente nem com o servidor), ele poderia ser utilizado por Botao e por qualquer outro objeto capaz de ligar/desligar um dispositivo:
CONCLUSÃO
O Princípio da Inversão de Dependência é um princípio essencial para um bom design orientado a objetos, ao passo que o oposto leva a um design engessado e procedural.
Identificar abstrações e inverter as dependências garantem que o software seja mais flexível e robusto, estando melhor preparado para mudanças.
Encerramos assim a série sobre os princípios SOLID, que juntos formam um conjunto de boas práticas que devemos ter em nosso cinto de utilidades e que devemos aplicar sempre que pudermos para melhorar a qualidade do design e da arquitetura do software.
—————————–
Toda a série:
Princípio da Responsabilidade Única (SRP)
Princípio do Aberto/Fechado (OCP)
Princípio da Substituição de Liskov (LSP)
Princípio da Segregação de Interface (ISP)
Princípio da Inversão de Dependência (DIP)
Eai Castilho, tudo bem ?
Poderia mostrar em um post futuro, como realizar DI através de um Container.
Abraços.
CurtirCurtir
Olá, alguém (tem nome? 🙂 )
Tenho que dar vazão a uns rascunhos e aí formulo algo.
Não tem segredo.
Você basicamente precisa configurar o container no ponto de entrada da app. Em uma app ASP.NET MVC, este ponto é o global.asax, onde você define seu custom Controller Factory.
Também existe o pacote Ninject.MVC3 (NuGet) que agiliza ainda mais para uso com o Ninject (sem a criação de um ControllerFactory).
[]s!
CurtirCurtir
Olá Castilho!
Excelente série de posts! Muito clara e didática. Parabéns o obrigado!
CurtirCurtir
Obrigado, Leandro!
Fico feliz que tenha conseguido passar a ideia!
[]s
CurtirCurtir
Olá Castilho!
Fechei os 05 princípios, show de bola! Não pare de postar!
Obrigado Robson! Abçsss
CurtirCurtir
Obrigado pelo feedback, Matheus.
Em breve mais boas práticas e design de software.
[]s
CurtirCurtir
Cara, muito bacana.
Parabéns pelo conjunto de posts.
Abraço!
CurtirCurtir
Obrigado pelo feedback, Jordão.
Continue acompanhando…
[]s
CurtirCurtir
se no caso a interface dispositivo fosse uma classe abstrata, eu estaria violando o princípio de inversão de dependêmcia?
CurtirCurtir
Não. O princípio é o mesmo.
[]s
CurtirCurtir
Você explica muito bem, parabéns, consegui entender esses princípios só depois que li sua explicação!
CurtirCurtir
Obrigado, “Alguém” 🙂
Sempre tento escrever/ilustrar da forma mais clara possível.
[]s
CurtirCurtir
Nossa muito show essa serie sobre SOLID.
Entendi mais aqui do que com meu professor.
Obrigado, sempre estarei acompanhando seu site e post.
CurtirCurtir
Olá, Gerson!
Obrigado pelo feedback.
Fico feliz que tenha te ajudado.
Qquer coisa, estamos aí.
[]s
CurtirCurtir
Estou usando vários de seus exemplos da “trilha” SOLID em minha aulas na HighTech. Os alunos entendem com muita facilidade. Obrigado pelo compartilhamento de conhecimento. Admiro muito seu trabalho.
CurtirCurtir
Obrigado, camarada.
“Isto fica feliz em ser útil”.
[]s e boa sorte nas aulas!
CurtirCurtir
Obrigado pelo post. Estava com dificuldade em me adaptar, clareou bastante.
CurtirCurtir
Obrigado, Elvir.
Qualquer coisa, estamos aí.
[]s
CurtirCurtir
Parabéns, muito bom o artigo.
CurtirCurtir
Excelente série! Clara, simples e objetiva! Vai ajudar bastante a pensar de forma diferente antes de iniciar um projeto.
CurtirCurtir
Obrigado, Cláudio!
Sim. A qualidade só tende a aumentar. Sucesso!
CurtirCurtir
valeu mesmo cara por suas explicações muito boas obrigado !
CurtirCurtir
Obrigado, Jonatas!
CurtirCurtir
Excelente série sobre SOLID! Parabéns e obrigado!
CurtirCurtir
Obrigado, Anderson!
CurtirCurtir
Primeiramente, obrigado!
Material de alta qualidade. Valeu cada minuto.
Parabéns pelo trabalho.
Sucesso!
CurtirCurtir
Muito obrigado, Gregório!
CurtirCurtir
Boa explicação! Obrigado.
CurtirCurtir
Obrigado, Tobias!
[]s
CurtirCurtir
Acompanhei a série dos 5 posts esses dias, espetacular a clareza que conseguiu colocar em um assunto que considero bastante complexo. Parabéns Robson!
E obrigado, me ajudou demais a entender os princípios SOLID.
CurtirCurtir
Oi, Willian
Fico feliz que os posts tenham ajudado!
Valeu!
[]s
CurtirCurtir
Gostei bastante!!
CurtirCurtir
Obrigado!
CurtirCurtir