Como Refatorar Seu Código Com Muitos If-Else? Part 2

Dário Prazeres - Sep 19 - - Dev Community

Como vimos no post anterior existem várias estrategias de refatorar o codigo quando ele tem muitos If-Else, só para relembrar:

1. Early return
2. Tabelas de decisão
3. Polimorfismo
4. Delegação de funções

Early Return

Early Return: é a abordagem que elimina as outras ramificações e concluído as decisões com retornos imediatos, mesmo se tais condições forem falsas. Como podemos ver:

public class CalculadoraDesconto
{
    public decimal CalculoDesconto(Cliente cliente, Pedido pedido)
    {
        if (cliente.IsPremium)
        {
            return pedido.QuantiaTotal > 100 ? pedido.QuantiaTotal * 0.1m : pedido.QuantiaTotal * 0.05m;
        }
        else
        {
            return pedido.QuantiaTotal > 200 ? pedido.QuantiaTotal * 0.15m : pedido.QuantiaTotal * 0.1m;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Acima temos uma função com a capacidade de fazer um retorno rápido usando operador ternário, agora veremos o cálculo da Complexidade Ciclomática:

Analise: temos 3 pontos de decisão:

  • if (cliente.IsPremium) (1 decisão),
  • pedido.QuantiaTotal > 100 (dentro do primeiro if),
  • pedido.QuantiaTotal > 200 (dentro do else).

Cálculo:
N = 3
E = 6
P = 1
M = E - N + 2P
M = 6 - (3) + 2(1) = 5

Tabelas de Decisão

Tabelas de decisão é uma técnica usada para simplificar a lógica condicional em código, especialmente quando se tem muitos if-else. Elas ajudam a mapear entradas para saídas, eliminando a necessidade de escrever várias condições aninhadas.

public class CalculadoraDesconto
{
    public decimal CalculoDesconto(Cliente cliente, Pedido pedido)
    {
        decimal descontoPercentual = ObterDescontoPercentual(cliente.IsPremium, pedido.QuantiaTotal);
        return pedido.QuantiaTotal * descontoPercentual;
    }

    private decimal ObterDescontoPercentual(bool isPremium, decimal quantiaTotal)
    {
        if (isPremium)
        {
            return quantiaTotal > 100 ? 0.1m : 0.05m;
        }
        else
        {
            return quantiaTotal > 200 ? 0.15m : 0.1m;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Como vimos no código acima, repartiu-se as funções isso para que só depois se fizesse o calculo e não sou acabou por usar a abordagem Early Return na segunda função, o que esteticamente melhorou mas a sua complexidade ciclomática continua a mesma como podemos ver:

Analise: temos 3 pontos de decisão:

  • if (cliente.IsPremium) (1 decisão),
  • pedido.QuantiaTotal > 100 (dentro do primeiro if),
  • pedido.QuantiaTotal > 200 (dentro do else).

Cálculo:
N = 3
E = 6
P = 1
M = E - N + 2P
M = 6 - (3) + 2(1) = 5

Polimorfismo

O polimorfismo é um dos pilares da programação orientada a objetos que permite que diferentes classes respondam de maneiras distintas a uma mesma mensagem (método). Ele possibilita que métodos de mesmo nome, em diferentes classes, tenham comportamentos variados, sem que o código cliente precise saber das diferenças.

Para termos mais detalhes de como funciona veja o exemplo abaixo:

public abstract class Cliente
{
    public abstract decimal CalcularDesconto(Pedido pedido);
}

public class ClientePremium : Cliente
{
    public override decimal CalcularDesconto(Pedido pedido)
    {
        return pedido.QuantiaTotal > 100 ? pedido.QuantiaTotal * 0.1m : pedido.QuantiaTotal * 0.05m;
    }
}

public class ClienteNormal : Cliente
{
    public override decimal CalcularDesconto(Pedido pedido)
    {
        return pedido.QuantiaTotal > 200 ? pedido.QuantiaTotal * 0.15m : pedido.QuantiaTotal * 0.1m;
    }
}
Enter fullscreen mode Exit fullscreen mode

Como vimos criou-se uma classe abstrata chamada Cliente que tem um método chamado CalcularDesconto este método é subscrito nas outras duas funções ClientePremium e ClienteNormal. Esta abordagem permitem fazer cálculos de forma independente e sem condições aninhadas.

Analise: temos 3 pontos de decisão:

  • Na classe ClientePremium: pedido.QuantiaTotal > 100 (1 decisão),
  • Na classeClienteNormal: pedido.QuantiaTotal > 200 (1 decisão).

Cálculo:
N = 1
E = 2
P = 1
M = E - N + 2P
M = 2 - (1) + 2(1) = 3

Esta abordagem requer mais organização por outro lado esta abordagem é mais propensa a escalabilidade. Sem falar que a Complexidade ciclomática é muito inferior que as duas anteriores.

Funções Delegadas

Funções Delegadas (ou simplesmente Delegates) é um conceito de programação que permite tratar métodos como objetos. Em linguagens como C#, um delegate é uma referência a um método e pode ser passado como argumento para outras funções, armazenado em variáveis ou retornado de funções, tornando o código mais flexível e modular.

public class CalculadoraDesconto
{
    private Func<Pedido, decimal> ObterCalculoDesconto(Cliente cliente)
    {
        if (cliente.IsPremium)
        {
            return pedido => pedido.QuantiaTotal > 100 ? pedido.QuantiaTotal * 0.1m : pedido.QuantiaTotal * 0.05m;
        }
        else
        {
            return pedido => pedido.QuantiaTotal > 200 ? pedido.QuantiaTotal * 0.15m : pedido.QuantiaTotal * 0.1m;
        }
    }

    public decimal CalculoDesconto(Cliente cliente, Pedido pedido)
    {
        var calcularDesconto = ObterCalculoDesconto(cliente);
        return calcularDesconto(pedido);
    }
}
Enter fullscreen mode Exit fullscreen mode

Analise: temos 3 pontos de decisão:

  • if (cliente.IsPremium) (1 decisão),
  • Dentro do retorno da função delegada, há outra decisão para pedido.QuantiaTotal.

Cálculo:
N = 2
E = 4
P = 1
M = E - N + 2P
M = 4 - (2) + 2(1) = 4

Conclusão

Algumas das complexidades ciclomáticas tiveram valores diferentes, umas iguais ao if-else aninhado e outras muito inferiores, não é regra mais isso dependerá muito do exercício que estas criar e levarás em conta a melhor abordagem.

Podemos ver que a complexidade ciclomatíca ajuda muito analisar as abordagens e hoje já existem softwares que verificam esta complexidade. Como programador será difícil as vezes de verificar se este é a melhor forma de fazer, mas convenhamos de que códigos com muitos If-elses não são agradáveis de se ver por mais que esta a funcionar e que quando iremos refatorar será como pisar em ovos. Treine até o ponto de teres olho clinico de analisar a melhor via para ti e para os que poderão mexer nesse código.

. . . .
Terabox Video Player