C#

1 dez, 2020

C# – Princípio Aberto/Fechado (OCP)

Publicidade

Vamos recordar o princípio Aberto/Fechado ou Open/Closed.

Na programação orientada a objetos, o princípio aberto/fechado afirma que:

 “entidades de software (classes, módulos, funções, etc.) devem estar abertas para extensão, mas fechadas para modificação”;

Isso significa que as entidades podem permitir que seu comportamento seja estendido sem modificar seu código-fonte.

Dê uma boa espiada no código abaixo:

public class CartaoCredito
    {
        private int _TipoCartaoCredito;
        public int TipoCartaoCredito { get; set; }
        public double GetDesconto(double custoMensal)
        {
            if (_TipoCartaoCredito == 1)
            {
                return custoMensal * 0.05;
            }
            else
            {
                return custoMensal * 0.01;
            }
        }
    }

Notou algo de errado ?

Pois bem, o código acima pode parecer bom, no entanto, se quisermos oferecer descontos para outro tipo de cartão de crédito, precisaremos modificar o código existente.

Por exemplo, se desejamos oferecer descontos específicos para outros tipos de cartão de crédito, precisamos fazer isso adicionando mais instruções IF ao método GetDesconto.

Ao modificar o código existente, acabamos de violar o princípio Aberto/Fechado.

Então como podemos oferecer o desconto para outros tipos de cartão de crédito sem modificar o código existente ?

Podemos encapsular o que varia, no exemplo, seria o cálculo do desconto por tipo de cartão de crédito.

Assim podemos usar a herança e definir a classe CartaoCredito com um método virtual, que poderá ser sobrescrito, por classes que representam cada uma delas um tipo de cartão de crédito.

Ou ainda podemos definir a classe CartaoCredito como abstrata e com o método GetDesconto() também abstrato que deverá ser implementado por quem herdar da classe.

Vamos fazer isso.

O código da classe CartaoCredito deve ficar assim:

 abstract class CartaoCredito
    {
        public abstract double GetDesconto(double custoMensal);
    }

Definimos uma classe abstrata CartaoCredito com um método abstrato GetDesconto().

Agora vamos criar as classes para os tipos de cartão de créditos para os quais vamos oferecer o desconto:

1- Cartão Visa

class CartaoVisa : CartaoCredito
    {
        public override double GetDesconto(double custoMensal)
        {
            return custoMensal * 0.05;
        }
    }

2- Cartão MasterCard

class CartaoMasterCard : CartaoCredito
    {
        public override double GetDesconto(double custoMensal)
        {
            return custoMensal * 0.08;
        }
    }

Podemos testar usando o código abaixo na classe Program:

class Program
    {
        static void Main(string[] args)
        {
            CartaoCredito cartao = new CartaoVisa();
            var desconto1 = cartao.GetDesconto(100);
            Console.WriteLine($"visa : {desconto1} %");
            cartao = new CartaoMasterCard();
            var desconto2 = cartao.GetDesconto(100);
            Console.WriteLine($"master card : {desconto2} %");
            Console.ReadLine();
        }
    }

Executando o código iremos obter:

Além desta abordagem poderíamos também usar outras implementações, mas o que importa é que agora o código da classe ficou fechado para modificação e aberto para ser estendido.

Para incluir outro cartão basta criar uma classe do tipo do cartão e herdar da classe abstrata CartaoCredito e implementar o seu desconto.

Poderíamos continuar refatorando o código e criar um fábrica para criar instâncias de cartões mas isso é assunto para outro artigo.

E estamos conversados…