Como último post sobre os princípios de design SOLID, vamos analizar um pouco o Princípio da Inversão de Dependência (Dependency Inversion Principle – DIP). Como os outros posts da série, o artigo de Robert C. Martin [1] foi utilizado como base para a discussão.
Dependency Inversion Principle
O conceito deste princípio é um pouco abstrato, mas com alguns exemplos poderemos analisar de uma maneira mais prática. A ideia central é de que classes de um nível alto não devem depender de classes de um nível mais baixo. Vamos entender o que são classes de nível alto e nível baixo através do exemplo citado em [2].
Suponha uma classe FuncionarioDAO que busca os funcionários de um determinado turno:
Obs: DAO (Data Access Object) é um padrão de projeto Core Java2EE (Java 2, Enterprise Edition) que encapsula mecanismos para acessar dados [4], neste exemplo, a classe DAO encapsula mecanismos para consultar dados de funcionários.
public class FuncionarioDAO { public ArrayList<String> buscaPorTurno(Turno turno){ // Busca no banco os funcionário do turno passado como parâmetro } }
Neste exemplo, a classe FuncionarioDAO é uma classe de alto nível de abstração e a classe ArrayList da Java Collections é uma classe de um nível mais baixo de abstração. A ArrayList fornece a infraestrutura necessária para que a FuncionarioDAO funcione, assim a classe FuncionárioDAO é de um nível mais alto que a ArrayList.
Suponha que um código recebe o resultado e precisa ordená-lo, esse retorno será sempre um ArrayList, assim, o método de ordenação estará preso a esta classe. Caso um algoritmo mais eficiente utilize outra estrutura, ele não poderá ser usado, a menos que o sistema passe por uma grande mudança no seu design. Seria necessário percorrer todo o código que estivesse ligado a esta classe e trocar pela nova implementação. Além disso, outros problemas também poderiam surgir, que são descritos mais detalhadamente em [2].
A ideia do princípio então é inverter a dependência, fazendo com que as classes de alto nível não dependam diretamente de uma classe de baixo nível, objetivando facilitar mudanças e manutenções futuras. Este é um dos conceitos chave em Orientação a Objetos [3]:
Programe voltado para interface e não para implementação
Como visto no post anterior, a API de Collections do Java segue o Interface Segregation Principle (ISP), oferecendo um conjunto de interfaces para vários tipos de usos. Assim, se a classe DAO acima estivesse conforme o DIP, uma alteração da estrutura interna não causaria danos a toda a aplicação, pois a dependência seria de uma Interface e não de uma Implementação específica.
Padrões de Projeto
O princípio da inversão de dependência é bastante presente no design dos vários padrões de projeto, pois todos eles definem uma interface, para que não haja uma dependência forte de implementações. Um grande exemplo de aplicação do princípio é o padrão Bridge, que define interfaces para favorecer um baixo acoplamento no design do código.
Um outro padrão que é bem ligado ao DIP é o Dependency Injection [5], que ainda não foi comentado aqui no blog. Este padrão sugere que as dependências de uma classe (por exemplo: uma conexão com o banco de dados) sejam injetados na classe. Desta forma, além de inverter a dependência, a classe não precisa se preocupar com o ciclo de vida das suas dependências (no exemplo da conexão, a classe não precisa abrir ou fechar a conexão, apenas recebe uma referência para a conexão e a utiliza).
Se gostou do post compartilhe com seus amigos e colegas, senão, comente o que pode ser melhorado. Possui alguma outra opinião ou alguma informação adicional? Comenta ai! 😀
Referências:
[1] www.objectmentor.com/resources/articles/dip.pdf
[2] Silveira, P. et. al. Introdução à Arquitetura e Design de Software. Rio de Janeiro: Elsevier, 2012.
[3] GAMMA, Erich et al. Padrões de Projeto: Soluções reutilizáveis de software orientado a objetos.
[4] http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html