Este é o quinto e último artigo da série Princípios SOLID – Boas práticas de programação com C#. Nele falaremos da última letra do acrônimo do SOLID: DIP – Dependency Inversion Principle. Você pode ler o artigo anterior clicando aqui.

Princípio da Inversão da Dependência: módulos de alto nível não devem depender de módulos de baixo nível. Ambos devem depender de abstrações.

Na Orientação a Objetos, todo o fluxo do mundo real é abstraído para o código se comportar o mais semelhante possível com a realidade. O princípio DIP é mais uma forma de organização para melhorar essa codificação da realidade: dependa somente de abstrações e não de implementação.

Isso gera um ganho enorme para desacoplamento entre as classes, uma vez que, se o comportamento de uma mudar, a outra não sofrerá impacto já que depende somente da abstração.

Acoplamentos sempre existirão, agora, o que vale a pena ponderar é a qualidade desses acoplamentos. Logo, depender de abstrações ou de classes estáveis é o ideal, porque a mudança não impactará em quem os está utilizando.

Retornando à solução proposta no primeiro princípio do SRP, ainda há o que melhorar. Observe que a classe FuncionarioServices está diretamente dependente da implementação de Funcionario e EmailServices. Caso alguma dessas duas sejam alteradas, nossa classe FuncionarioServices também sofrerá alteração. Utilizar a inversão de dependência nesse caso faria com que a dependência das classes Funcionario e EmailServices fosse invertida, removendo essa responsabilidade de FuncionarioServices.

Uma forma de realizar essa alteração é utilizar a injeção de dependência, que é basicamente fazer com que a FuncionarioServices utilize apenas a abstração das classes que ela precisa para funcionar. Isso é feito injetando a dependência pelo construtor, como segue:

public class FuncionarioServices : IFuncionarioServices
    {
        private readonly IFuncionarioRepository funcionarioRepository;
        private readonly IEmailServices emailServices;

        public FuncionarioServices(
            IEmailServices emailServices, 
            IFuncionarioRepository funcionarioRepository)
        {
            this.emailServices = emailServices;
            this.funcionarioRepository = funcionarioRepository;
        }

        public string AdicionarFuncionario(Funcionario funcionario)
        {
            if (!funcionario.Validar())
                return "Dados inválidos";

            this.funcionarioRepository.AdicionarFuncionario(funcionario);

            this.emailServices.Enviar("[email protected]", funcionario.Email.Endereco, "Bem Vindo", "Parabéns está Cadastrado");

            return "Funcionario cadastrado com sucesso";
        }
    }

Os princípios do SOLID se complementam, e como podemos ver nesse caso, para aplicar a inversão de dependência é preciso programar orientado a interfaces (conforme prega o ISP) além do SRP, uma vez que agora cada classe ficará responsável por ter somente uma única responsabilidade. Dessa forma conseguimos depender somente das abstrações necessárias (IEmailServices e IFuncionarioRepository):

public interface IEmailServices
    {
        void Enviar(string de, string para, string assunto, string mensagem);
    }
public interface IFuncionarioRepository
    {
        void AdicionarFuncionario(Funcionario funcionario);
    }
public interface IFuncionarioServices
    {
        string AdicionarFuncionario(Funcionario funcionario);
    }

Assim, definimos todos os contratos estabelecidos para que cada classe implemente seguindo a regra de negócio.

A dica aqui é:

  • Não dependa de implementações, dependa de abstrações.

Conclusão

O SOLID é uma diretriz para a construção de código mais enxuto e legível. Isso ajuda muito na manutenção futura (afinal o mundo é dinâmico e quem nunca escutou um “será que você poderia fazer essa alteraçãozinha pequena aqui pra mim?”). Precisamos lembrar sempre que desenvolvemos sistemas não apenas para cumprir o prazo, mas para facilitar essa manutenção. Além do mais, aplicar o SOLID também é importante para facilitar a escalabilidade do negócio. É importante lembrar também que, embora os exemplos foram feitos em C#, as regras macros do SOLID são aplicáveis para toda e qualquer linguagem que utilize OO e em alguns casos na funcional também (como o SRP).

Os princípios servem para direcionar o pensamento durante a codificação. Mas é sempre adaptável à realidade que você está. Tudo deve ser feito com ponderação e pensamento crítico ao contexto em que você está desenvolvendo.

Caso não tenha acompanhado a série, é possível acompanhar pelos links abaixo:

  • Parte 1:  SRP – Single Responability Principle
  • Parte 2: OCP – Open Closed Principle
  • Parte 3: LSP – Liskovs Substitution Principle
  • Parte 4: ISP – Interface Segregation Principle

Referências

The Single Responsibility Principle

The Open Closed Principle

Solid Relevance

.NET – Princípios SOLID – Princípio da Inversão da Dependência

PIRES, E. SOLID: Teoria e Prática.

ANICHE, M. Orientação a Objetos e SOLID para ninjas. São Paulo – Casa do Código

MARTIN, C. R. Código Limpo – Habilidades Práticas do Agile Software. Rio de Janeiro 2011 – Alta Books.

Samyla Dutra

Mineira, atuo na área de desenvolvimento desde 2017 e sou graduada em Engenharia de Computação pelo CEFET-MG. Gosto de entender a profundidade do backend e como melhorar a escrita de código. E isso se torna melhor em equipe! Amo estar em contato com a natureza, trilhar montanhas, ler livros e cozinhar.