Abrace as instruções de guarda e pare de usar expressões condicionais aninhadas!

Adquira o hábito de escrever juntos! Este é o sexto dia da minha participação no "Nuggets Daily New Plan · April Update Challenge", clique para ver os detalhes do evento .

motivação

As expressões condicionais geralmente vêm em dois sabores:

  • Ambos os ramos condicionais são comportamento normal
  • Apenas uma ramificação condicional é um comportamento normal, a outra ramificação é anormal

Esses dois tipos de expressões condicionais servem a propósitos diferentes, que devem ser mostrados no código:

  • Se ambas as ramificações são de comportamento normal, uma expressão condicional da forma if...else... deve ser usada

  • Se uma condição for extremamente rara, ela deve ser verificada separadamente e retornada da função assim que a condição for verdadeira

    Essas verificações separadas são muitas vezes referidas como "cláusulas de guarda"

A essência de substituir expressões condicionais aninhadas por guardas é dar atenção especial a uma ramificação. Se você usar uma construção if-then-else, você colocará peso igual na ramificação if e na ramificação else. A mensagem para o leitor de tal estrutura de código é que cada ramo é igualmente importante. A instrução guard está dizendo ao leitor: "Esta situação não é o que interessa à lógica central desta função. Se isso acontecer, por favor, faça a limpeza necessária e saia."

A noção de que "toda função pode ter apenas uma entrada e uma saída" está profundamente arraigada em alguns programadores. Quando trabalho com o código que eles escrevem, geralmente preciso usar instruções de guarda em vez de expressões condicionais aninhadas. As linguagens de programação atuais impõem apenas uma entrada por função, e a regra de "saída única" não é tão útil. Manter o código claro é a chave: se uma única saída torna a função mais legível, use uma única saída; caso contrário, não.

prática

Selecione a lógica condicional mais externa que precisa ser substituída e substitua-a por uma instrução guard.

teste.

Se necessário, repita os passos acima.

Se todas as instruções de guarda produzirem o mesmo resultado, você poderá combiná-las usando [Merge Conditional Expressions].

caso

Calcule os salários a serem pagos aos funcionários. Apenas os funcionários que ainda estão trabalhando na empresa precisam ser pagos, então esta carta

O número precisa verificar se há duas situações de "funcionário que não está mais trabalhando".

    public Long payAmount(Employee employee) {
        long result;
        if (employee.isSeparated) {
            result = 0;
        } else {
            if (employee.isRetired) {
                result = 0;
            } else {
                // logic to compute amount
                lorem.ipsum(dolor.sitAmet);
                consectetur(adipiscing).elit();
                sed.do.eiusmod = tempor.incididunt.ut(labore) && dolore(magna.aliqua);
                ut.enim.ad(minim.veniam);
                result = someFinalComputation();
            }
        } return result;
    }
复制代码

A lógica condicional aninhada torna difícil ver o que o código realmente significa. Somente quando nenhuma das duas expressões condicionais atuais é verdadeira, esse código realmente inicia seu trabalho principal. Portanto, as instruções de guarda permitem que o código expresse seu significado com mais clareza

foto. Como sempre, gosto de dar pequenos passos, então lido primeiro com a lógica condicional superior.

    public Long payAmount(Employee employee) {
        long result;
        if (employee.isSeparated) {
            result = 0;
        }
        if (employee.isRetired) {
            result = 0;
        } else { // logic to compute amount
            lorem.ipsum(dolor.sitAmet);
            consectetur(adipiscing).elit();
            sed.do.eiusmod = tempor.incididunt.ut(labore) && dolore(magna.aliqua);
            ut.enim.ad(minim.veniam);
            result = someFinalComputation();
        } return result;
    }
复制代码

Após fazer essa modificação, executo o teste e passo para a próxima etapa.

    public Long payAmount(Employee employee) {
        long result;
        if (employee.isSeparated) {
            return 0l;
        }
        if (employee.isRetired) {
            return 0l;
        }

        lorem.ipsum(dolor.sitAmet);
        consectetur(adipiscing).elit();
        sed. do.eiusmod = tempor.incididunt.ut(labore) && dolore(magna.aliqua);
        ut.enim.ad(minim.veniam);
        result = someFinalComputation();
        return result;
    }
复制代码

Neste ponto, a variável de resultado é inútil, então eu a excluo:

    public Long payAmount(Employee employee) {
        if (employee.isSeparated) {
            return 0l;
        }
        if (employee.isRetired) {
            return 0l;
        }
        lorem.ipsum(dolor.sitAmet);
        consectetur(adipiscing).elit();
        sed. do.eiusmod = tempor.incididunt.ut(labore) && dolore(magna.aliqua);
        ut.enim.ad(minim.veniam);
        return someFinalComputation();
    }
复制代码

É sempre bom poder reduzir uma variável mutável.

reverter a condição

Muitas vezes podemos reverter a expressão condicional para substituir expressões condicionais aninhadas por guardas.

public int adjustedCapital(Instrument anInstrument) {
  int result = 0;
  if (anInstrument.capital > 0) {
    if (anInstrument.interestRate > 0 && anInstrument.duration > 0) {
      result = (anInstrument.income / anInstrument.duration) * anInstrument.adjustmentFactor;
    }
  }
  return result;
}
复制代码

Substitua um por um. Mas desta vez ao inserir a instrução guard, preciso reverter a condição correspondente:

public int adjustedCapital(Instrument anInstrument) {
  int result = 0;
  if (anInstrument.capital <= 0) {
    return result;
  }
  if (anInstrument.interestRate > 0 && anInstrument.duration > 0) {
    result = (anInstrument.income / anInstrument.duration) * anInstrument.adjustmentFactor;
  }
  return result;
}
复制代码

A próxima condição é um pouco mais complicada, então faço a inversão em duas etapas. Primeiro adicione uma operação NOT lógica:

public int adjustedCapital(Instrument anInstrument) {
  int result = 0;
  if (anInstrument.capital <= 0) {
    return result;
  }
  if (!(anInstrument.interestRate > 0 && anInstrument.duration > 0)) {
    return result;
  }
  result = (anInstrument.income / anInstrument.duration) * anInstrument.adjustmentFactor;
  return result;
}
复制代码

Mas deixar um NOT lógico em uma expressão condicional como essa estragaria minha cabeça, então eu simplifiquei para:

public int adjustedCapital(Instrument anInstrument) {
  int result = 0;
  if (anInstrument.capital <= 0) {
    return result;
  }
  if (anInstrument.interestRate <= 0 || anInstrument.duration <= 0) {
    return result;
  }
  result = (anInstrument.income / anInstrument.duration) * anInstrument.adjustmentFactor;
  return result;
}
复制代码

Essas duas linhas de lógica produzem o mesmo resultado, então posso combiná-las com [Merge Conditional Expressions]:

public int adjustedCapital(Instrument anInstrument) {
  int result = 0;
  if (anInstrument.capital <= 0 || anInstrument.interestRate <= 0 || anInstrument.duration <= 0) {
    return result;
  }
  result = (anInstrument.income / anInstrument.duration) * anInstrument.adjustmentFactor;
  return result;
}
复制代码

Neste ponto, a variável result faz duas coisas: primeiro eu a defino como 0, que representa o valor de retorno quando a instrução guard é acionada; e então eu a atribuo com o resultado do cálculo final. Eu posso remover esta variável completamente, evitar dupla responsabilidade com uma variável e reduzir mais uma variável variável.

public int adjustedCapital(Instrument anInstrument) {
  if (anInstrument.capital <= 0 || anInstrument.interestRate <= 0 || anInstrument.duration <= 0) {
    return 0;
  }
  return (anInstrument.income / anInstrument.duration) * anInstrument.adjustmentFactor;
}
复制代码

referir-se

  • "Reconstrução"
  • "Arquitetura Limpa"

Acho que você gosta

Origin juejin.im/post/7083509863132692494
Recomendado
Clasificación