不要这样做!
目前,你的calculateTax
方法就像一个包含四个实际calculateTax
方法的容器,分别是三个国家和一个无效情况。按照这种方式制作的任何其他方法都会是这样。遵循这个模式,您将在许多方法中使用许多开关(检查相同的一组情况),其中每种情况都包含案例的具体内容。但是这正是多态以更好的方式实现的!
像这样的模式非常明显地表明您没有充分利用面向对象,并且在没有其他原因的情况下,您绝对应该这样做。毕竟,这是Java,也是整个玩意儿的核心。
创建像TaxPolicy
这样的接口:
interface TaxPolicy {
BigDecimal calculateTaxFor(BigDecimal saleAmount);
}
创建一个实现它的类:
class NationalSalesTaxPolicy implements TaxPolicy {
String countryName;
BigDecimal salesTaxRate;
BigDecimal calculateTaxFor(BigDecimal saleAmount) {
return saleAmount.multiply(salesTaxRate);
}
}
然后,根据需要支持的每个国家创建此类的对象。我们可以将此列表封装到一个新类NationalSalesTaxCalculator
中,这将成为我们计算任何国家销售税的一站式商店:
class NationalSalesTaxCalculator {
static Map<String, NationalSalesTaxPolicy> SUPPORTED_COUNTRIES = Stream.of(
new NationalSalesTaxPolicy("POLAND", "0.23"),
new NationalSalesTaxPolicy("AUSTRIA", "0.20"),
new NationalSalesTaxPolicy("CYPRUS", "0.19")
).collect(Collectors.toMap(NationalSalesTaxPolicy::getCountryName, c -> c));
BigDecimal calculateTaxFor(String countryName, BigDecimal saleAmount) {
NationalSalesTaxPolicy country = SUPPORTED_COUNTRIES.get(countryName);
if (country == null) throw new UnsupportedOperationException("Country not supported");
return country.calculateTaxFor(saleAmount);
}
}
我们可以像这样使用它:
NationalSalesTaxCalculator calculator = new NationalSalesTaxCalculator();
BigDecimal salesTax = calculator.calculateTaxFor("AUSTRIA", new BigDecimal("100"));
System.out.println(salesTax);
需要注意的一些关键优点:
- 如果您要添加要支持的新国家,您只需创建一个新对象。 所有可能需要该对象的方法都会自动"做正确的事情",而无需手动找到它们所有的位置,以便添加新的if语句。
- 您可以根据需要调整功能。 例如,在我居住的地方(加拿大安大略省),不会为杂货收取销售税。 因此,我可以制作自己的
NationalSalesTaxPolicy
子类,具有更细致入微的逻辑。
甚至还有改进的空间。 注意NationalSalesTaxCalculator.calculateTaxFor()
包含一些特定于处理不受支持的国家的代码。 如果我们在该类中添加新操作,则每个方法都需要相同的null检查和错误抛出。
相反,可以重构为使用null object pattern。您可以实现一个UnsuppoertedTaxPolicy
,这是一个通过抛出异常来实现所有接口方法的类。 就像这样:
class UnsuppoertedTaxPolicy implements TaxPolicy {
public BigDecimal calculateTaxFor(BigDecimal saleAmount) {
throw new UnsupportedOperationException("Country not supported");
}
}
然后您可以执行
TaxPolicy countryTaxPolicy = Optional
.ofNullable(SUPPORTED_COUNTRIES.get(countryName))
.orElse(UNSUPPORTED_COUNTRY);
return countryTaxPolicy.calculateTaxFor(saleAmount);
这个"集中化"所有的异常到一个地方,使得它们更容易找到(因此更容易设置断点),更容易编辑(如果您想迁移异常类型或更改消息),并且它减少了其余代码的混乱程度,只需关注 happy case。
这是一个可工作的演示:https://repl.it/@alexandermomchilov/Polymorphism-over-ifswitch
java.util.Map
... ? - Oleksandr Pyrohov