关于枚举策略方法的疑问
为了计算所得税,我尝试使用枚举策略方法来使逻辑更加简洁。但最终我并不满意,主要是因为我必须为收入组别,限额和费率编写不同的枚举。这是因为它们都是不同性质的常量。但由于这个代码看起来不紧凑,似乎缺乏封装。关于枚举策略方法的疑问
我的担心是真的吗?请让我知道您的意见或更好的方法。
说,是所得税基团和相应的比率如下:
- 收入之间0 - 500000:10% 征税
- 收入之间500001 - 百万:收入的20%的应纳税
- 1000001 - 无限:30%可征税
例如,所得税适用于的1200000的收入将是200000(1200000 - 1000000) 30%500000(1000000 - 500000) + 20%的500000(500000 - 0) + 10% = 160000
代码 :
package itcalc;
public class IncomeTaxCalculatorImpl {
private enum IncomeGroup {
ONE(Limit.GROUP_ONE_LIMIT) {
@Override
public double calculate(double income) {
return income * Rate.GROUP_ONE_RATE.value/100;
}
},
TWO(Limit.GROUP_TWO_LIMIT) {
@Override
public double calculate(double income) {
return ((income - Limit.GROUP_ONE_LIMIT.maximum)
* Rate.GROUP_TWO_RATE.value/100)
+ ONE.calculate(Limit.GROUP_ONE_LIMIT.maximum);
}
},
THREE(Limit.GROUP_THREE_LIMIT) {
@Override
public double calculate(double income) {
return ((income - Limit.GROUP_TWO_LIMIT.maximum)
* Rate.GROUP_THREE_RATE.value/100)
+ TWO.calculate(Limit.GROUP_TWO_LIMIT.maximum
- Limit.GROUP_ONE_LIMIT.maximum)
+ ONE.calculate(Limit.GROUP_ONE_LIMIT.maximum);
}
};
private final Limit limit;
private enum Limit {
GROUP_ONE_LIMIT(0, 500000),
GROUP_TWO_LIMIT(500001, 1000000),
GROUP_THREE_LIMIT(1000001, Double.MAX_VALUE);
private final double minimum;
private final double maximum;
private Limit(double minimum, double maximum) {
this.minimum = minimum;
this.maximum = maximum;
}
}
private enum Rate {
GROUP_ONE_RATE(10), GROUP_TWO_RATE(20), GROUP_THREE_RATE(30);
private final double value;
private Rate(double value) {
this.value = value;
}
}
private IncomeGroup(Limit limit) {
this.limit = limit;
}
abstract double calculate(double income);
}
public double calculate(double income) {
for (IncomeGroup group : IncomeGroup.values()) {
if (income >= group.limit.minimum
&& income <= group.limit.maximum) {
return group.calculate(income);
}
}
throw new IllegalArgumentException("Invalid Income Value");
}
}
枚举是使代码更易读有用的,但我想你的代码是不是通常会单独引用常量ONE,TWO或THREE,在执行计算时更有可能需要遍历所有税收组。
如果您将纳税组常量与纳税计算算法分开,代码可能会更清晰。使用对象的数组,你可以这样写:
public static final TaxGroup[] TAX_GROUPS = new TaxGroup[] {
new TaxGroup(1000000, 0.3),
new TaxGroup(500000, 0.2),
new TaxGroup(0, 0.1)
};
然后你可以写一个算法来计算税收,而不是保持算术三个独立的副本:
int untaxed = income;
int tax = 0;
for(TaxGroup taxGroup : TAX_GROUPS) {
if(untaxed > taxGroup.lowerLimit) {
tax += (untaxed - taxGroup.lowerLimit) * taxGroup.rate;
untaxed = taxGroup.lowerLimit;
}
}
是Limit
和Rate
枚举在其他地方重复使用?如果没有,你可以摆脱他们,并修改IncomeGroup所必须的限度和速度元素:
ONE(0,500000,10)
这样,你将有少枚举和代码将是小更紧凑
你不不需要限制或费率类。你可以这样说,因为费率,限额和收入组之间存在一对一的对应关系 - 将他们代表的数值合并到收入组中,为组提供三个值:范围两个,百分比一个。即使你在其他地方使用这些值,你也可以做到这一点 - 只需将它们公开为Enums的最终字段即可。
顺便说一句,如果您正在使用双打,那么范围的最小值应该是最低的范围,而不是最大值加一。税收形式通常会给予这些价值,因为他们将收入汇到最近的美元。如果你不这样做,你可能会得到一个不属于这个范围的收入。
更顺带计算()可能应该是静态的,节省您的工作了,你是在哪个收入群体的麻烦。
正如我所期望的对于税务计算,随着时间的推移,您可能需要考虑越来越多的事实。例如。定义收入组的范围可能需要从数据库加载,因为这些可能会发生变化。同样,给定收入组的适用税率也可能发生变化。将这些范围硬编码到您的代码中不是一个好主意!
您可能想看看规则引擎背后的想法,例如正向链接。 JBoss的Drools手册在描绘如何使用规则引擎方面做得很好(并且思路在大多数规则引擎中传输)。无论如何,我认为枚举策略模式适用于更简单的业务案例(例如,打印给定对象,如org.joda.time.format.DateTimeFormatter
),但不适用于可能需要汇总多个对象中的事实以计算结果的更复杂案例(例如工资核算,税收,调节账簿等)
重新格式化的代码;如果不正确请回复。 – trashgod 2010-07-08 18:08:44