For computing Income Tax, I tried to use Enum Strategy approach to make the logic more concise. But in the end I’m not satisfied mainly because I had to write different enums for income groups, limits and rates. This was because they are all constants of different nature. But due to this the code doesn’t looks compact and seems to lack encapsulation.
Is my worry genuine? Please let me know your views or a better approach.
Say, Income Tax groups and corresponding rates are as follows:
- Income between 0 – 500000 : 10% taxable
- Income between 500001 – 1000000 : 20% taxable
- Income between 1000001 – Infinite : 30% taxable
For example, Income Tax applicable on an income of 1200000 would be 30 % of 200000 (1200000 – 1000000) + 20% of 500000 (1000000 – 500000) + 10% of 500000 (500000 – 0) = 160000
Code:
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");
}
}