C# - Encapsulando Regras de Negócio no Modelo


Hoje veremos como encapsular regras de negócio em propriedades das classes do modelo de domínio.

O primeiro pilar do paradigma da Programação Orientada a Objetos (POO) é o encapsulamento, e, se o encapsulamento não for feito de forma correta você corre o sério risco de que seu código esteja mal formado.

Para criar um exemplo claro e objetivo vamos definir um cenário onde temos uma classe Financiamento onde temos duas propriedades : DataInicioPagamento e DataEvento do tipo string:

    public class Financiamento
    {
        public string DataInicioPagamento { get; set; }
        public string DataEvento { get; set; }
    } 

A regra de negócio que devemos aplicar aqui  é a seguinte :

  1. Se o valor para DataInicioPagamento for maior do que DataEvento;
  2. Então DataEvento deverá ser definida com o valor da DataInicioPagamento;

A primeira tentativa de esboçar uma implementação para esta regra de negócio usando o encapsulamento é definir o seguinte código na classe Financiamento:

    public class Financiamento
    {
        public string DataInicioPagamento { get; set; }

        private string _dataEvento;
        public string DataEvento
        {
            get
            {
                if (DateTime.Parse(DataInicioPagamento) > DateTime.Parse(_dataEvento))
                {
                    return DataInicioPagamento;
                }
                else
                {
                    return _dataEvento;
                }
            }
            set
            {
                _dataEvento = value;
            }
        }
    }

Aparentemente este código implementa o encapsulamento e resolve a implementação da lógica de negócio.

Mas podemos melhorar o código nos seguintes aspectos:

Na propriedade DataEvento:

a- Precisamos verificar se DataEvento é um valor válido;

b- O método DateTime.Parse vai lançar uma exceção se o formato da data não estiver correto. Usar DateTime.TryParse é mais indicado pois ele não lança uma exceção se a data for inválida;

Abaixo vemos uma possível implementação mais refinada para a propriedade DataEvento:

        private string _dataEvento;
        public string DataEvento
        {
            get
            {               
               return _dataEvento;
            }
            set
            {
                if (_dataEvento == value)
                {
                    return;
                }
                //data do evento é válida
                if (DateTime.TryParse(value, CultureInfo.CurrentCulture,
                                        DateTimeStyles.None,
                                        out DateTime dataEvento))
                {
                    _dataEvento = value;
                    // se a data inicio do pagamento for válida
                    if (DateTime.TryParse(DataInicioPagamento,
                                            CultureInfo.CurrentCulture,
                                            DateTimeStyles.None,
                                            out DateTime dataInicioPagamento))
                    {
                        //Define data do evneto para data inicio do pagamento
                        if (dataInicioPagamento > dataEvento)
                        {
                            _dataEvento = DataInicioPagamento;
                        }
                    }
                }
                else
                {
                    throw new ArgumentNullException(nameof(value), "Data do evento inválida.");
                }
            }

No código além de usar DateTime.TryParse estamos definindo o uso da globalização de forma que o código vai poder ser executado em qualquer cultura.

Com esses ajustes feitos precisamos alterar o código para a propriedade DataInicioPagamento :

        private string _dataInicioPagamento;
        public string DataInicioPagamento
        {
            get
            {
                return this._dataInicioPagamento;
            }
            set
            {
                if (this._dataInicioPagamento == value)
                {
                    return;
                }
                //Verifica validada da data
                if (DateTime.TryParse(value, out DateTime dataInicioPagamento))
                {
                    this._dataInicioPagamento = value;
                    //Atribui o valor para DataEvento
                    if (DateTime.TryParse(this.DataEvento, out DateTime dataEvento))
                    {
                        if (dataInicioPagamento > dataEvento)
                        {
                            this._dataEvento = value;
                        }
                    }
                }
                else
                {
                    throw new ArgumentNullException(nameof(value), 
                               "O valor para DataInicioPagamento é inválido.");
                }
            }
        }

Aqui também estamos usando DateTime.TryParse e estamos validando o valor da propriedade.

Temos assim um código mais robusto e preparado para mudanças usando o encapsulamento.

E estamos conversados.

"E a paz de Deus, que excede todo o entendimento, guardará os vossos corações e os vossos pensamentos em Cristo Jesus."
Filipenses 4:7

Referências:


José Carlos Macoratti