通用计价的简单代码实现
什么场景该使用通用计价
如果商品的费用属性一直在变化,比如隔三岔五的新增某种费用(按新规则计算的新费用),作为开发人员的你每次需要胆战心惊的维护现有的计价接口,测试也需要花费大量时间验证对其他费用的影响。基于这一点,我在想如果初期把计价做成一个通用的计价接口,每次加费用我只需要关注新费用的计算规则,不需要去修改已有费用的规则计算代码,也就可以避免一些BUG的产生。
简单代码实现
总体思路是利用Spring的容器管理,项目启动时将所有计价类型加载在计价执行类中,具体调用方法和平时写代码一样注入就行。这个方法并没有在实际项目中使用。
1. 通用计价接口
import java.math.BigDecimal;
import java.util.Map;
public interface CommonValuation {
/**
* 计价类型
* @return
*/
String getValuationType();
/**
* 计价接口,子类实现自己的计价方式
* @param paramsJson
* @param result 保存所有的费用类型及金额
* @return
*/
void valuation(String paramsJson, Map<String, BigDecimal> result);
}
说明:这里定义了计价接口,具体的计价类型和计算规则由子类实现,这里会借助Spring来管理子类。
2. 计价接口的执行类
@Component
public class CommonValuationChain {
@Autowired
private ApplicationContext applicationContext;
private List<CommonValuation> commonValuationList = new ArrayList<>();
/**
* 加载项目中所有的费用计算类
*/
@PostConstruct
private void init() {
String[] commonValuationArr = applicationContext.getBeanNamesForType(CommonValuation.class);
for (String cvName : commonValuationArr) {
commonValuationList.add(applicationContext.getBean(cvName, CommonValuation.class));
}
// 可以通过 @Order 决定计价的顺序
AnnotationAwareOrderComparator.sort(commonValuationList);
}
public Map<String,BigDecimal> valuation(String paramsJson) {
// 保存所有的费用及对应的金额
Map<String,BigDecimal> result = new HashMap<>();
for(CommonValuation valuation : commonValuationList) {
valuation.valuation(paramsJson, result);
}
return result;
}
}
说明:这里是借助Spring的@PostConstruct注解,将所有的费用类型计算类加载到commonValuationList中,供业务方使用,子类也可以根据@Order注解决定计算的顺序。
3. 具体费用类型
@Component
@Order(4)
public class DiscountMoneyValuation implements CommonValuation{
/**
* 减免费
* @return
*/
@Override
public String getValuationType() {
return "discountMoney";
}
@Override
public void valuation(String paramsJson, Map<String, BigDecimal> result) {
// 伪代码,这里可以将 paramsJson 转换成需要的计价参数,计算真实价格
BigDecimal discountMoney = new BigDecimal("-10.6");
result.put(getValuationType(), discountMoney);
}
}
@Component
@Order(333)
public class TestMoneyValuation implements CommonValuation{
@Override
public String getValuationType() {
return "testMoney";
}
@Override
public void valuation(String paramsJson, Map<String, BigDecimal> result) {
// 伪代码,这里可以将 paramsJson 转换成需要的计价参数,计算真实价格
BigDecimal testMoney = new BigDecimal("100");
result.put(getValuationType(), testMoney);
}
}
4. 调用类
@Autowired
private CommonValuationChain commonValuationCore;
@Test
public void valuationTest() {
Map<String,BigDecimal> result = commonValuationCore.valuation(null);
for(Map.Entry<String,BigDecimal> price : result.entrySet()) {
System.out.println(price.getKey() + ",金额" + price.getValue());
}
}
5. 执行结果
总结
以上是我个人对于通用计价的一种实现,本人水平有限,暂时想不到更有扩展性、可用性的方法,如果大家有更好的方法可以在下方评论,同时欢迎大家进行指导和批评。