Finalmente chegamos à última parte sobre SOLID e pra encerrar, vamos conversar sobre o DIP (Dependency Inversion Principle) ou Princípio da Inversão de Dependência.

Seria injusto dizer que qualquer um dos princípios SOLID é mais importante que o outro. No entanto, provavelmente nenhum dos outros tem um efeito tão imediato e profundo em seu código do que o DIP.

Cogitar desenvolver um software sem levar em conta esse princípio é comprometer o projeto violando boas práticas de arquitetura.

Mantra ou Definição

Módulos de alto nível não devem depender de módulos de baixo nível. Mas sim ambos devem depender de abstrações.

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

Uma outra abordagem que gosto muito relacionado a esse princípio:

Dependa de uma abstração e não de uma implementação.

Este princípio foi definido por Robert C. Martin, também conhecido como Uncle Bob, em seu livro Agile Software Development, Principles, Patterns, and Practices que tempos depois ganhou uma versão para C# intitulado como Agile Principles, Patterns, and Practices in C#.

Agile Principles, Patterns, and Practices in C#
Figura 01 – Livro Agile Principles, Patterns, and Practices in C#.

Vamos ver algo bem comum que mostra a dependência de Classe1 para a Classe2:

Em Classe1 vemos: Classe2 obj = new Classe2();

Agora a Classe1 necessita consumir a Classe2 gerando assim uma dependência de uma implementação. Normalmente a Classe1 seria um módulo de alto nível e Classe2 um módulo de baixo nível.

Hã? Como assim?

Acredito que a maioria dos desenvolvedores já trabalhou com o padrão DAO (Data Access Object). O padrão DAO é um pattern que abstrai e encapsula os mecanismos de acesso a dados escondendo os detalhes da execução da origem dos dados. Veja um exemplo de código aplicando esse padrão:

Primeiro temos a classe ClienteDAO que encapsula os métodos de acesso a base de dados e realiza operações de CRUD (Create, Read, Update e Delete).


public class ClienteDAO
{
    public void Cadastrar(Cliente cliente)
    {
       //acessa a base e cadastra um cliente
    }
}

Depois temos a classe ClienteBO que representa uma classe de regra de negócio que manipula o objeto e ao término de sua ação, chama uma operação de gravação no banco de dados.


public class ClienteBO
{
   private ClienteDAO obj;

   public void CadastrarCliente(Cliente cliente)
   {
       obj = new ClienteDAO();
       obj.Cadastrar(cliente);
   }
}

 

É uma excelente ideia encapsular o acesso a dados, com isso tem a vantagem do reuso principalmente evitando duplicação de código. Porém o pecado fica por conta da dependência da implementação da classe ClienteDAO.

Veja no diagrama de classe essa dependência:

dependecia de implementação
Figura 02 – Diagrama de Classe demonstrando a dependência por uma classe concreta.

 

Será que não seria melhor a classe ClienteBO saber que precisa do comportamento de ClienteDAO, mas sem precisar saber quem é ClienteDAO?

Como todos sabem, ou deveriam saber, a orientação a objeto imita muitos dos comportamentos da vida real, do nosso cotidiano. Por exemplo, se uma pessoa precisa ter acesso a internet, ela contrata uma empresa que provê serviço de internet. A primeira coisa que a empresa de internet vai fazer é fornecer um contrato com os serviços que ele deve prestar ao contratante. A pessoa que contratou não precisa saber ao certo que são os responsáveis pela sustentação daquele serviço, quem é o presidente da empresa, os atendentes, técnicos e etc. Ela só precisa que o serviço que está garantido em contrato seja atendido.

Vamos fazer valer essa afirmação no código!

A primeira tarefa seria extrair o comportamento de ClienteDAO em uma abstração:


public interface IClienteDAO
{
   void Cadastrar(Cliente cliente);
}

Depois IClienteDAO deve ser implementado em ClienteDAO

 public class ClienteDAO : IClienteDAO
 {
     public void Cadastrar(Cliente cliente)
     {
        //acessa a base e cadastra um cliente
     }
 }

Por fim, a classe ClienteBO não vai mais depender de uma implementação e sim de uma abstração, não interessa pra ela como se cadastra um Cliente, qual o banco de dados ou quem realmente faz isso (lembra da empresa de internet?), só importa pra ClienteBO que existe um contrato que prevê o cadastro de uma entidade Cliente.

 public class ClienteBO
 {
     private IClienteDAO _clienteDAO;

     public ClienteBO(IClienteDAO clienteDAO)
     {
         _clienteDAO = clienteDAO;
     }

     public void CadastrarCliente(Cliente cliente)
     {
        _clienteDAO.Cadastrar(cliente);
     }
 }

Veja agora como ficou no diagrama de classe. ClienteBO agora não depende mais de ClienteDAO e sim de uma interface, ou seja, o que interessa é somente o comportamento abstrato de ClienteDAO.

dependendo de uma interface

Figura 03 – Diagrama de Classe demonstrando a dependência por abstração.

Aplicando o DIP, estamos invertendo a dependência, já que dentro de ClienteBO contém apenas uma abstração do comportamento de ClienteDAO e estamos também invertendo o controle, pois ele é fornecido de fora da classe. Veja:


 var cliente = new Cliente();
 var clienteBO = new ClienteBO(new ClienteDAO());
 clienteBO.CadastrarCliente(cliente);

Dá pra ficar ainda melhor

Existe disponível no mercado contêineres de inversão de dependência como Unity, Ninject entre outros. Esses frameworks auxiliam na tarefa de injetar dependência via construtor, propriedades e métodos, além de evitar o forte acoplamento. Pretendo em breve escrever um artigo sobre injeção de dependência através do uso do Ninject e ASP.NET MVC.

Por enquanto é só pessoal, aqui fechamos nossa série sobre SOLID, até a próxima!

Referências:

 .NET – Apresentando o padrão DAO – Data Access Object

SOLID design principles in .NET: the Dependency Inversion Principle and the Dependency Injection pattern

Dependency inversion principle

Diego Neves

Desenvolvedor de software, graduado em Análise e Desenvolvimento de Sistemas pela Universidade Nove de Julho, atualmente trabalha na FCamara e tem foco no mundo .NET, possui algumas certificações como MCSD Web Applications, MCSD App Builder, MCSA Web Applications, Microsoft Specialist, MCP e ITIL V3 Foundation.

Facebook LinkedIn 

Comentários

comentarios