Pour écrire des branchements conditionnels (if), vous pouvez trouver des techniques de retour précoce qui n'approfondissent pas l'imbrication à divers endroits. Personnellement, je ne pense pas que tout devrait être écrit avec des retours anticipés, et devrait être utilisé en fonction de la situation. De plus, c'est cet article qui m'a inspiré pour écrire un article. Surtout, la section des commentaires a été une expérience d'apprentissage.
J'ai une politique selon laquelle les retours anticipés ne doivent être utilisés que pour la gestion des erreurs et la logique métier doit être écrite en toute sécurité de manière conditionnelle. Ce point est expliqué dans l'exemple de code ci-dessous.
À titre d'exemple simple, considérons la logique de calcul du prix de paiement en tenant compte de la taxe à la consommation et du taux d'actualisation. Si certaines conditions sont remplies, la taxe à la consommation sera le prix hors taxe à la consommation. Si le taux d'actualisation remplit également certaines conditions, il sera réduit de 1 par rapport au prix après prise en compte de la taxe à la consommation. Dans un souci de simplicité, nous n'entrerons pas dans le détail sur la présence ou l'absence de taxe à la consommation et les conditions d'application des remises, mais nous la mettrons en œuvre avec un drapeau indiquant si elle est applicable ou non.
//Calculez le montant payé par le client
public decimal CalculatePaymentPrice(decimal price, bool canRemoveTax, bool canDiscount)
{
if (price < 0)
{
throw new ArgumentOutOfRangeException("Veuillez saisir une valeur de 0 ou plus pour le prix du produit.");
}
else if (canRemoveTax)
{
//Remise appliquée sans taxe à la consommation
if (canDiscount)
{
return price * 0.9m;
}
else
{
return price;
}
}
else
{
//Remise appliquée avec taxe à la consommation
if (canDiscount)
{
return price * 1.08m * 0.9m;
}
else
{
return price * 1.08m;
}
}
}
//Calculez le montant payé par le client
public BigDecimal CalculatePaymentPrice(BigDecimal price, boolean canRemoveTax, boolean canDiscount) {
if (price.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException("Veuillez saisir une valeur de 0 ou plus pour le prix du produit.");
} else if (canRemoveTax) {
//Remise appliquée sans taxe à la consommation
if (canDiscount) {
return price.multiply(new BigDecimal("0.9"));
} else {
return price;
}
} else {
//Remise appliquée avec taxe à la consommation
if (canDiscount) {
return price.multiply(new BigDecimal("1.08")).multiply(new BigDecimal("0.9"));
} else {
return price.multiply(new BigDecimal("1.08"));
}
}
}
2018/05/01 postscript Comme vous pouvez le voir dans la section des commentaires, une exception est levée même s'il s'agit d'une erreur commerciale. Normalement, vous ne devez pas lever d'exception pour les erreurs professionnelles. Il s'agit d'un effet néfaste en raison de la simplification de l'exemple de code et n'est pas soumis à la refactorisation. Ce que je voulais dire dans cet exemple, c'est que je ne veux pas mettre les erreurs commerciales dans la logique, il est donc normal de les éliminer tôt.
En réalité, un plan de refactoring consiste à effectuer le processus de vérification des prix à l'avance et à appeler la méthode CalculatePaymentPrice après avoir passé le contrôle.
public decimal CalculatePaymentPriceAfterRefactoring(decimal price, bool canRemoveTax, bool canDiscount)
{
//Évitement des erreurs
if (price < 0)
{
throw new ArgumentOutOfRangeException("Veuillez saisir une valeur de 0 ou plus pour le prix du produit.");
}
//Taux de taxe à la consommation fixe
decimal taxRate;
if (canRemoveTax)
{
taxRate = 0m;
}
else
{
taxRate = 0.08m;
}
//Taux de remise confirmé
decimal discountRate;
if (canDiscount)
{
discountRate = 0.9m;
}
else
{
discountRate = 1.0m;
}
//Calculer le prix de paiement
return price * (1m + taxRate) * discountRate;
}
public BigDecimal CalculatePaymentPriceAfterRefactoring(BigDecimal price, boolean canRemoveTax,
boolean canDiscount) {
//Évitement des erreurs
if (price.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException("Veuillez saisir une valeur de 0 ou plus pour le prix du produit.");
}
//Acquisition du taux de la taxe à la consommation
BigDecimal taxRate;
if (canRemoveTax) {
taxRate = BigDecimal.ZERO;
} else {
taxRate = new BigDecimal("0.08");
}
//Obtenez un taux de réduction
BigDecimal discountRate;
if (canDiscount) {
discountRate = new BigDecimal("0.9");
} else {
discountRate = BigDecimal.ONE;
}
//Calculer le prix de paiement
return price.multiply(taxRate.add(BigDecimal.ONE)).multiply(discountRate);
}
En modifiant le flux de traitement de la partie de calcul du prix de paiement, chaque traitement peut être séparé. Si vous êtes préoccupé par les variables temporaires taxRate et discountRate, vous pouvez faire de la partie de la détermination du taux de taxe à la consommation et de la détermination du taux d'actualisation une méthode. Pour la gestion des erreurs, si vous appliquez un retour anticipé et écrivez une autre logique métier en toute sécurité avec des conditions complètes, n'y a-t-il pas de problème en tant que politique de mise en œuvre? Enfin, j'ai osé écrire sur la taxe à la consommation finalisée avec un retour anticipé.
Ce code est concis, mais si vous l'écrivez dans if-else, vous pouvez vérifier la couverture de la condition et vous sentir à l'aise. D'un autre côté, beaucoup de gens disent que le code est trop court et que l'un ou l'autre convient. .. ..
private decimal GetTaxRate(bool canRemoveTax)
{
if (canRemoveTax)
{
return 0m;
}
return 0.08m;
}