代表链是否合适

时间:2013-10-07 22:56:08

标签: java algorithm design-patterns recursion

我在接受采访时被要求实施业务规则

要求变更。他们总是这样做:

  
      
  1. 评估低于100,000美元的任何金额的20%费用。
  2.   
  3. 评估100,000美元至500,000美元之间任何金额的10%费用。
  4.   
  5. 评估500,000美元以上任何金额的5%费用
  6.   

计算任意金额x的费用。

示例:鉴于600,000美元的发票,费用应为65,000美元。

鉴于50,000美元的发票,费用应为10,000美元。

鉴于200,000美元的发票,费用应为30,000美元。

我使用了CofR,但是面试官然后询问他们是否超过3个条件,如果我们创建了n个类来处理每个请求。

除了为每个条件编写一个非常长的递归函数检查之外,他们是更好的方法吗?

3 个答案:

答案 0 :(得分:2)

我猜这位采访者暗示像责任链模式这样的东西对于像这样的问题会有点过度设计。还有一个论点,即你的实现类实际上将承担相同的责任,因为它们都是基于给定的输入计算一个数量,只是使用不同的参数。

我可能会用两个简单的类来做这件事。可以根据输入值计算百分比费率,并使用该费率返回费用金额。

如果需要添加第四个条件,只需将其添加到包含速率计算的类中。对于这样一个简单的问题,我不明白为什么它需要比这更复杂。

修改

我和@chrylis一样思考,因为有一个类通过处理有序的费率列表来执行计算。

class Rate {
    int rangeSize;
    double commission;

    Rate(int rangeSize, double commission){
        this.rangeSize = rangeSize;
        this.commission = commission;
    }

    int computeForAmount(int amount) {
        if (amount <= 0) {
            return 0;
        }
        return (int) (Math.min(amount, this.rangeSize) * this.commission);
    }
}

class FeeCalculator {

    List<Rate> rates = Arrays.asList(
            new Rate(100, 0.2),
            new Rate(400, 0.1),
            new Rate(500, 0.05));

    int calculateCommission(int startingAmount) {
        int commission = 0;
        int remainingAmount = startingAmount;

        for (Rate rate : this.rates) {
            commission += rate.computeForAmount(remainingAmount);
            remainingAmount -= rate.rangeSize;
        }

        return commission;
    }

}

我承认我通过调用rate.rangeSize来打破封装并不是完全高兴,但它确实展示了我试图表达的设计。

答案 1 :(得分:2)

当链条的成员具有截然不同的规则时,CoR是有用的,但在这种情况下,所有规则基本相同(如果金额超过X则收取一定的百分比)。而不是独立的类,只需要一个类似结构的类,它保持最小的数量和百分比,另一个查找相应的费用:

class FeeSchedule {
    static class Entry implements Comparable<Entry> {
        int threshold;
        int percentage;

        int compareTo(Entry other) {
            // sort by percentage, descending
        }

    SortedSet<Entry> feeTable;

    int calculateFee(int invoiceAmount) {
        for(Entry e : feeTable)
            if(invoiceAmount > e.threshold)
                return (invoiceAmount * e.percentage);

        // error condition; return 0?
    }
}

答案 2 :(得分:0)

我认为在这种情况下,一个简单的策略模式就足够了。类似的东西:

interface FeeAssessor {
    public double assessFee(double invoice);
}

FeeAssessor feeAssessor = new FeeAssessor() {
        // logic goes here
    };

double calculateFee(double invoice) {
    return feeAssessor.assessFee(invoice);
}

对于您提供的简单业务逻辑,我认为在一个assessFee()函数中实现它会更简单。您可以实现不同的(简单的)并根据需要交换“策略”对象。如果费用评估算法依赖于彼此独立的多个变化因素,那么您可以进一步将它们分解为多种策略方法。