如何在C#中简化复杂的长嵌套if else语句

时间:2014-07-31 15:09:22

标签: c#

我有如下所示的功能,它根据五个输入参数计算税额。 对于输入参数的每个组合,存在匹配的“条件”,其仅仅是返回语句,例如,如果输入参数是:

nationality == "German" and 
netIncome == 45000 and 
(birthDate >= 01.01.1950 && birthDate < 01.01.1960) and 
childrenCount == 1 
then tax value is 0.15%

如果我们考虑所有输入参数组合,if else语句会变得非常长并且嵌套。

public static decimal GetTax(int netIncome, string nationality, DateTime birthDate, int childrenCount, bool handicapped)
{
    if (nationality == "DE")
    {
        if (handicapped)
        {
            // condition1
            return 0;
        }

        if (birthDate >= new DateTime(1930, 1, 1) && birthDate < new DateTime(1936,1,1))
        {
            if (childrenCount == 1)
            {
                // condition2
                return 0.05m;
            }
            else
            {
                // other conditions
            }
        }
        else if(birthDate >= new DateTime(1950, 1, 1))
        {
            if (netIncome >= 30000 && netIncome < 40000)
            {
                if (childrenCount == 1)
                {
                    // condition3
                    return 0.15m;
                }
                else if (childrenCount == 2 || childrenCount == 3)
                {
                    // other conditions
                    return Convert.ToDecimal(netIncome * 0.10);
                }
                else
                {
                    // other conditions
                }
            }
            if (netIncome >= 40000 && netIncome < 50000)
            {
                if (childrenCount >= 1 && childrenCount < 3)
                {
                    // other conditions
                    return Convert.ToDecimal(netIncome * 0.17);
                }
                else if (childrenCount >= 3 || childrenCount < 5)
                {
                    // other conditions
                    return Convert.ToDecimal(netIncome * 0.16);
                }
                else
                {
                    // other conditions
                }
            }
        }
        else
        {

        }
    }
    else if (nationality == "FR")
    {

    }
    else if (nationality == "IT")
    {

    }

    // just to satisfy the compiler
    throw new Exception("The input parameters don't match any condition!");
}

问题是:如何简化上述if else语句,使其成为更容易理解且更易于维护的代码?

我提出了一个简单的(我希望)解决方案,我想提出一下:

(1)我创建了一个名为Condition的类,如下所示

private class Condition
{
    private readonly decimal tax;
    private readonly Predicate<string> nationalityPredicate;
    private readonly Predicate<DateTime> birthDatePredicate;
    private readonly Predicate<int> childrenCountPredicate;
    private readonly Predicate<int> netIncomePredicate;
    private readonly Predicate<bool> handicappedPredicate;

    public Condition(decimal taxParameter, Predicate<string> nationality, Predicate<DateTime> birthDate, Predicate<int> netIncome, Predicate<int> childrenCount, Predicate<bool> handicapped)
    {
        this.tax = taxParameter;
        this.nationalityPredicate = new Predicate<string>(nationality);
        this.birthDatePredicate = new Predicate<DateTime>(birthDate);
        this.netIncomePredicate = new Predicate<int>(netIncome);
        this.childrenCountPredicate = new Predicate<int>(childrenCount);
        this.handicappedPredicate = new Predicate<bool>(handicapped);
    }

    public bool IsTrue(string nationality, DateTime birthDate, int netIncome, int childrenCount, bool handicapped)
    {
        if (this.nationalityPredicate(nationality))
        {
            if (this.birthDatePredicate(birthDate))
            {
                if (this.netIncomePredicate(netIncome))
                {
                    if (this.childrenCountPredicate(childrenCount))
                    {
                        if (this.handicappedPredicate(handicapped))
                        {
                            return true;
                        }
                    }
                }
            }
        }

        return false;
    }

    public decimal CalculateTax()
    {
        Debug.WriteLine(this.tax);
        return this.tax;
    }
}

此类对应于上面GetTax()函数中嵌套if else语句中的一个条件。例如当5个输入参数为Ethnic =“DE”,birthDate =“01.01.1955”,netIncome = 35,000,childrenCount = 1且disapped = false时,此条件的税率为0.15

此类用于分解长复杂的嵌套if else语句。 对于GetTax()函数中的每个return语句,我们使用一个Condition类instant。

(2)我创建了TaxCalculator类,它使用Condition类作为内部帮助类,如下所示

    public class TaxCalculator
    {
        // List of conditions
        private readonly List<Condition> conditions = new List<Condition>();

        /// <summary>
        /// Constructor. All the conditions are created and initialized here. 
        /// The conditions initialized in the constructor correspond to the nested if else statements in the GetTax() function.
        /// </summary>
        public TaxCalculator()
        {
            // This corresponds to Condition1 in the 'GetTax()' function
            Condition condition = new Condition(
                0,
                nationality => nationality == "DE",
                birthDate => true,
                netIncome => true,
                childrenCount => true,
                handicapped => handicapped);

            this.conditions.Add(condition);

            // This corresponds to Condition2 in the 'GetTax()' function 
            condition = new Condition(
                0.05m,
                nationality => nationality == "DE",
                birthDate => (birthDate >= new DateTime(1930, 1, 1)) && (birthDate < new DateTime(1936, 1, 1)),
                netIncome => true,
                childrenCount => childrenCount == 1,
                handicapped => !handicapped);

            this.conditions.Add(condition);

            // This corresponds to Condition3 in the 'GetTax()' function
            condition = new Condition(
                0.15m,
                nationality => nationality == "DE",
                birthDate => birthDate >= new DateTime(1950, 1, 1),
                netIncome => (netIncome >= 30000 && netIncome < 40000),
                childrenCount => childrenCount == 1,
                handicapped => !handicapped);

            this.conditions.Add(condition);
        }

        /// <summary>
        /// This function corresponds to the GetTax() function, it determines which Condition object corresponds
        /// to the input parameters.
        /// </summary>
        public decimal CalculateTax(string nationality, DateTime birthDate, int netIncome, int childrenCount, bool handicapped)
        {
            // iterate the conditions
            foreach (Condition c in this.conditions)
            {
                // check if the input parameters apply the current condition
                if (c.IsTrue(nationality, birthDate, netIncome, childrenCount, handicapped))
                {
                    // if yes, return the result of this condition
                    return c.CalculateTax();
                }
            }

            // in case of no matching condition raise an exception.
            throw new Exception("TaxCalculator class didn't match any condition for parameters...etc.");
        }
}

TaxCalculator类对应于上面GetTax()函数中的长嵌套if else语句。 该类使用简单的lambda表达式在构造函数中创建Condition对象,每个Condition对象对应于GetTax()函数中的一个条件(标记为// Condition1,// Condition2和// Condition3)

(3)要计算给定输入参数集的税,我们执行以下操作:

    TaxCalculator taxCalculator = new TaxCalculator();

    // check for conditions

    // condition3
    decimal tax = taxCalculator.CalculateTax("DE", new DateTime(1985, 1, 1), 33000, 1, false);

    // condition2 
    tax = taxCalculator.CalculateTax("DE", new DateTime(1933, 1, 1), 0, 1, false);

    // condition1
    tax = taxCalculator.CalculateTax("DE", new DateTime(1977, 1, 1), 0, 0, true);

问题:

  • 是否有更好,更简单的解决方案,易于维护?
  • 有任何优化或更正建议吗?

1 个答案:

答案 0 :(得分:0)

我会写第一个如果这样:

public bool IsTrue(string nationality, DateTime birthDate, int netIncome, int childrenCount, bool handicapped)
{
    return (this.nationalityPredicate(nationality) && 
            this.birthDatePredicate(birthDate) &&
            this.netIncomePredicate(netIncome) &&
            this.childrenCountPredicate(childrenCount) &&
            this.handicappedPredicate(handicapped))
}

对于其余的它是一个经典的规则检查引擎,似乎很好。 Perhap只是反转最后一次抛出异常。这是一个选择问题,但例外不是正常的应用程序流程恕我直言。如果出现问题,你应该抛出异常,如果出现问题则不应该抛出异常。喜欢:

public decimal CalculateTax(string nationality, DateTime birthDate, int netIncome, int childrenCount, bool handicapped)
{
    var result = this.condition.FirstOrDefault(c => c.IsTrue(nationality, birthDate, netIncome, childrenCount, handicapped));

    if(result == null) 
        throw new Exception("TaxCalculator class didn't match any condition for parameters...etc.");

    return result.CalculateTax();           
}

Perhap只是要小心这个名字。 “是真的” ?什么是真的?从商业角度来看,甚至从技术角度来看,它意味着什么?我确信这对你来说非常清楚,但对于那些必须维护它的人来说,他将不得不看一下方法定义(在最好的情况下,如果不是整个规则引擎)来理解这个“ IsTrue“的意思是。至少你有评论,但一个好的方法名称,恕我直言,比数千行评论更好。