.NET Conceito - O princípio das dependências explícitas

 Neste artigo estou apresentar o princípo das dependêcias explícitas ou Explicit Dependencies Principle.

O que vem a ser esse tal de Princípio das Dependências Explícitas ou Explicit Dependencies Principle ?

Bem, esse princípio diz o seguinte :

Métodos e classes devem exigir explicitamente (normalmente através de parâmetros de método ou parâmetros de construtor) qualquer objeto de colaboração que eles precisam para funcionar corretamente.

Se suas classes exigem que outras classes executem suas operações, essas outras classes são dependências. Essas dependências estão implícitas se elas existirem somente no código dentro de sua classe e não em sua interface pública. As dependências explícitas aparecem com mais frequência no construtor de um objeto, para dependências a nível de classe ou na lista de parâmetros de um determinado método, para mais dependências locais.

Classes com dependências implícitas custam mais para manter do que aquelas com dependências explícitas. Elas são mais difíceis de testar porque são mais fortemente acopladas aos seus colaboradores. Elas são mais difíceis de analisar para efeitos colaterais, porque a base de código da classe inteira deve ser pesquisada para instanciações de objetos ou chamadas para métodos estáticos. Elas são mais frágeis e mais fortemente acopladas aos seus colaboradores, resultando em desenhos mais rígidos e sujeitos a erros.

As classes com dependências explícitas são mais honestas. Eles afirmam muito claramente o que elas exigem para desempenhar sua função particular. Elas tendem a seguir o Principle of Least Surprise ou Princípio da Menor Surpresa ao não afetar partes da aplicação que não explicitamente demonstraram que precisavam afetar.

Dependências explícitas podem ser facilmente trocadas com outras implementações, seja em produção ou durante testes ou depuração. Isso as torna muito mais fáceis de manter e muito mais abertas à mudança.

O Princípio das Dependências Explícitas está intimamente relacionado com o Princípio de Inversão de Dependência e ao Princípio de Hollywood.

Princípio de HollywoodNão nos telefone, nós telefonaremos para você:  “O princípio de Hollywood  proporciona uma maneira de evitar o colapso das dependências (…). Colapso das dependências é o que acontece quando você tem componentes de alto nível dependendo de componentes de baixo nível que dependem de componente de alto nível que dependem de componentes laterais que dependem de componentes de baixo nível, e assim por diante.” (Freeman, 2005, p. 244)

Neste princípio temos que : “..os componentes de alto nível dizem aos componentes de baixo nível: Não nos telefone, nós telefonaremos para você.” (Freeman, 2005, p. 244)

Vamos examinar o código abaixo de uma aplicação Console usando a linguagem C#.

Temos neste código 3 classes:

  1. Contexto

  2. Cliente

  3. RespostaPersonalizada

No método Main() criamos uma instância da classe Cliente(), definimos os valores de suas propriedades e atribuimos a instância criada à propriedade ClienteAtual da classe Contexto.

A seguir criamos uma instância da classe RespostaPersonalizada() e invocamos o método GetResposta() que irá fazer o seguinte:

using System;
using System.IO;

namespace CSharp_DependenciasExplicitas_Implicitas
{
    class Program
    {
        static void Main(string[] args)
        {
            var cliente = new Cliente()
            {
                CorFavorita = "Azul",
                Titulo = "Sr.",
                NomeCompleto = "Jose Carlos Macoratti"
            };

            Contexto.ClienteAtual = cliente;

            var resposta = new RespostaPersonalizada();

            Console.WriteLine(resposta.GetResposta());
            Console.ReadLine();
        }
    }

    public static class Contexto
    {
        public static Cliente ClienteAtual { get; set; }

        public static void Log(string mensagem)
        {
            using (StreamWriter logArquivo = new StreamWriter(
                Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
                    "logArquivo.txt")))
            {
                logArquivo.WriteLine(mensagem);
            }
        }
    }

    public class Cliente
    {
        public string CorFavorita { get; set; }
        public string Titulo { get; set; }
        public string NomeCompleto { get; set; }
    }

    public class RespostaPersonalizada
    {
        public string GetResposta()
        {
            Contexto.Log("Gerando uma resposta personalizada.");
            string formataString = "Boa {0}, {1} {2}! Que tal de um brinde {3} hoje ?";
            string horaDoDia = "tarde";

            if (DateTime.Now.Hour < 12)
            {
                horaDoDia = "manhã";
            }
            if (DateTime.Now.Hour > 17)
            {
                horaDoDia = "noite";
            }


            return String.Format(formataString, horaDoDia,
                Contexto.ClienteAtual.Titulo,
                Contexto.ClienteAtual.NomeCompleto,
                Contexto.ClienteAtual.CorFavorita);
        }
    }
}

A classe RespostaPersonalizada esta claramente acoplada ao sistema de arquivos e ao relógio do sistema, bem como a uma instância particular do cliente por meio da classe Contexto global.

Se fôssemos refatorar essa classe para tornar suas dependências explícitas, uma das possibilidades seria o código a seguir:

using System;
using System.IO;
namespace Dependencias_Explicitas
{
    class Program
    {
        static void Main(string[] args)
        {
            var cliente = new Cliente()
            {
                CorFavorita = "Azul",
                Titulo = "Sr.",
                NomeCompleto = "Jose Carlos Macoratti"
            };
            var resposta = new RespostaPersonalizada(new LogArquivos(), new SystemDateTime());
            Console.WriteLine(resposta.GetResposta(cliente));
            Console.ReadLine();
        }
    }
    public interface ILogger
    {
        void Log(string mensagem);
    }
    public class LogArquivos : ILogger
    {
        public void Log(string mensagem)
        {
            using (StreamWriter logFile = new StreamWriter(
                Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
                    "logArquivo.txt")))
            {
                logFile.WriteLine(mensagem);
            }
        }
    }
    public class Cliente
    {
        public string CorFavorita { get; set; }
        public string Titulo { get; set; }
        public string NomeCompleto { get; set; }
    }
    public interface IDateTime
    {
        DateTime Now { get; }
    }
    public class SystemDateTime : IDateTime
    {
        public DateTime Now
        {
            get
            {
                return DateTime.Now;
            }
        }
    }
    public class RespostaPersonalizada
    {
        private readonly ILogger _logger;
        private readonly IDateTime _dataHora;
        public RespostaPersonalizada(ILogger logger, IDateTime dataHora)
        {
            this._dataHora = dataHora;
            this._logger = logger;
        }
        public string GetResposta(Cliente cliente)
        {
             _logger.Log("Gerando uma resposta personalizada.");
            string formataString = "Boa {0}, {1} {2}! Que tal de um brinde {3} hoje ?";
            string horaDoDia = "tarde";
            if (DateTime.Now.Hour < 12)
            {
                horaDoDia = "manhã";
            }
            if (DateTime.Now.Hour > 17)
            {
                horaDoDia = "noite";
            }
            return String.Format(formataString, horaDoDia,
                cliente.Titulo,
                cliente.NomeCompleto,
                cliente.CorFavorita);
        }
    }
}

Agora as dependências de log e do tempo foram colocadas como parâmetros do construtor, enquanto o cliente foi colocado como parâmetro do método.

Para funcionar, a classe RespostaPersonalizada() vai precisar receber via construtor uma instância da classe LogArquivos() e SystemDataTime() :

 var resposta = new RespostaPersonalizada(new LogArquivos(), new SystemDateTime());

visto que ela faz o registro do log e precisa obter a hora do sistema para montar a resposta personalizada.

Suas dependências agora são explícitas e a classe é honesta em deixar isso bem claro para quem for usá-la.

O resultado final é um código que só pode ser usado quando as coisas que ele precisa forem fornecidas para ele. (definir o escopo das dependências a nível de classe ou de método vai depender de como eles são usados pela classe ou quantos métodos referencia o item em questão, etc.).

Nota: Poderíamos melhorar ainda mais o código usando a injeção de dependência. Fica como um exercício.

fonte : http://deviq.com/explicit-dependencies-principle/

Pegue o código usado no artigo aqui : CSharp_DependenciasExplicitas_Implicitas.zip

Sabendo, amados irmãos, que a vossa eleição é de Deus;Porque o nosso evangelho não foi a vós somente em palavras, mas também em poder, e no Espírito Santo, e em muita certeza, como bem sabeis quais fomos entre vós, por amor de vós.
1 Tessalonicenses 1:4,5

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

  Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

Referências:


José Carlos Macoratti