具有许多 if else 条件的函数的可维护性和可读性

Maintainability and Readability of a function which has many if else conditions

我有一个计算薪水的函数,如下所示。未显示 CalculateHRA 和 CalculaAllowance 函数定义。 CalculateSalary 有很多 if-else 条件,如果添加了任何条件,这个函数就会不断增长。除了 if-else 之外,还有更好的方法来处理这个问题吗?

public class SalaryDTO{
 public int Salary{get;set;}
 public int Bonus {get;set;}
 public int HRA {get;set;}
 public int Allowance {get;set;}
 public string Output{get;set;}
}

public void CalculateSalary(List<SalaryDTO> salaryDTO)
{
  foreach(var a in salaryDTO)
  {
    if(a.Salary > 0 && a.Bonus >0)
    {
      a.HRA = CalculateHRA(a.Salary,a.Bonus);
      a.Allowance = CalculateAllowance(a.Salary,a.Bonus);
      a.Output = "Profit";
    }
   if(a.Salary < 0 && a.Bonus < 0)
    {
      a.HRA = CalculateHRA(a.Salary,a.Bonus);
      a.Allowance = CalculateAllowance(a.Salary,a.Bonus);
      a.Output = "Loss";
    }
    if(a.Salary > 0 && a.Bonus == 0)
    {
      a.HRA = CalculateHRA(a.Salary,a.Bonus);
      a.Allowance = 10;
      a.Output = "Profit";
    }
   if(a.Salary == 0 && a.Bonus < 0)
    {
      a.HRA = 20;
      a.Allowance = CalculateAllowance(a.Salary,a.Bonus);
      a.Output = "Profit";
    }
    if(a.Salary <0 && a.Bonus >0)
    {
     //Somecode and conditions similar to above 
    }
  }
}

也许首先要考虑的是谁负责知道如何计算工资。也许您需要一个 Salary class,其唯一职责是在您的业务中模拟“薪水”的概念。 class 可能包括一些处理数据的方法。

    public class Salary
    {
        public Salary(int salaryValue, int bonus)
        {
            SalaryValue = salaryValue;
            Bonus = bonus;
            HRA = CalculateHRA();
            Allowance = CalculateAllowance();
        }

        public int SalaryValue { get; private set; }
        public int Bonus { get; private set; }
        public int HRA { get; private set; }
        public int Allowance { get; private set; }
        public string Output => SalaryValue < 0 ? "Loss" : "Profit";

        private static int CalculateHRA()
        {
            // ...
        }

        private static int CalculateAllowance()
        {
            // ...
        }
    }

这与 DTO 不同。 DTO 包含数据但没有行为。

要计算 HRA 和津贴,您可能需要检查条件,但只需要检查适用于此任务的条件。同样值得考虑的是,“Salary class 是否应该负责计算 HRA?”也许,也许不是。在第二轮重构中,您可以尝试一下,看看专用的 HRA class 是否可以提高阅读和理解。津贴也一样。

使用负责实施细节的 Salary 模型,您可以从 DTO 列表中获取完全计算的薪水列表,如下所示:

public IEnumerable<Salary> CalculateSalary(List<SalaryDTO> salaryDTOs) =>
    salaryDTOs.Select(dto => new Salary(dto.Salary, dto.Bonus));

这当然不是唯一的方法。拥有良好的自动化单元测试作为安全网以确保行为正确非常重要。根据以下简单原则做出决定:

  • 将数据和相关方法封装在一起,
  • 每个 class 或方法应该只负责一件事。