问题描述:在创建合同时,会选择一个何时付款的策略,比如,目前策略有:
? ? 合同执行开始时付款100%,
? ? 合同执行结束后付款100%
? ? 合同每月结算当月应付金额
? ? ...
?
并且付款的策略还会改变。
最初的代码使用一大串if...else...,如下:
class="java" name="code"> public List<PaymentPlan> resolve(ExecutionUnit unit, String paymentTermsNumber) { if (unit != null) { if (PaymentTermEnum.OTHER.getValue().equals(paymentTermsNumber)) { return resolve0(unit); } else if (PaymentTermEnum.FIVE_DAY_NEXT_MONTH.getValue().equals(paymentTermsNumber)) { return resolve1(unit); } else if (PaymentTermEnum.BEFORE_END_MONTH_PAY_PREVIEW_MONTH.getValue().equals(paymentTermsNumber)) { return resolve2(unit); } else if (PaymentTermEnum.BEFORE_END_MONTH_PAY_NEXT_MONTH.getValue().equals(paymentTermsNumber)) { return resolve3(unit); } ... } return new ArrayList<PaymentPlan>(); } private List<PaymentPlan> resolve0(ExecutionUnit unit) { List<PaymentPlan> paymentPlanList = new ArrayList<PaymentPlan>(); if (unit == null) { return paymentPlanList; } Contract contract = contractService.getByNumber(unit.getContractnum()); if (contract == null) { return paymentPlanList; } PaymentPlan filter = new PaymentPlan(); filter.setContractId(contract.getId()); return paymentPlanService.list(filter); } ....
?和旧社会妇女的裹脚布一样,又臭又长。而且当策略改变的时候,还需要把裹脚布再加长一点,这时很可能疏忽了而没有添加(程序猿们经常会拿疏忽了,忘记了当借口,你懂的)。
当受不了恶心的时候就是进步的前兆,因此决定重构这部分代码,首先代码中判断的时候用到了枚举类PaymentTermEnum,但是里面只有下面这些:
public enum PaymentTermEnum { // 其他 OTHER("0"), // 当月广告款次月5日结清 FIVE_DAY_NEXT_MONTH("1"), // 每月30日前向乙方支付上月广告款. BEFORE_END_MONTH_PAY_PREVIEW_MONTH("2"), // 每月30日前向乙方支付下月广告款 BEFORE_END_MONTH_PAY_NEXT_MONTH("3"), // 每个季度执行完广告后,30日内支付相应的款项 AFTER_QUARTER_PAY_WITHIN_THIRTY("5"), // 每个季度执行完广告后,45日内支付相应的款项. AFTER_QUARTER_PAY_WITHIN_FORTH_FIVE("6"), // 每个季度执行完广告后,在当季内支付相应的款项. AFTER_QUARTER_PAY_WITHIN_THIS_QUARTER("7"), // 每个月执行完当月的广告后,30日内支付相应的款项. AFTER_END_MONTH_PAY_WITHIN_THIRTY("8"), // 每个月执行完当月的广告后,在当月月末支付100%的款项. AFTER_END_MONTH_PAY_END_THIS_MONTH("9"), // 每张执行单执行前预付100%的款项. PAY_BEFORE_EXECUTE("10"), // 每张执行单执行前预付30%的款项,执行完付剩余70%的款项. PAY_THIRTY_BEFORE_EXECUTE_SEVENTY_AFTER_EXECUTED("11"), // 每张执行单执行前预付50%的款项,执行完付剩余50%的款项. PAY_HALF_BEFORE_EXECUTE_HALF_AFTER_EXECUTED("12"), // 每张执行单执行完广告后,30日内支付相应的款项. AFTER_EXECUTED_PAY_WITHIN_THIRTY_DAY("13"), // 每张执行单执行完广告后,5个工作日内支付相应的款项. AFTER_EXECUTED_PAY_WITHIN_FIVE_DAY("14"); private String value; private PaymentTermEnum(String value) { this.value = value; } public String getValue() { return this.value; } }
?这只能避免在解析的方法中不使用类似于"0","1"这种tricky的字符串。虽然有点小用,但是没有完全发挥枚举的其他作用。
首先,每个策略最终都是要解析成 List<PaymentPlan>,即付款计划的列表,可以在枚举类中使用一个抽象方法,这样枚举中的每个常量必须要实现,此时枚举类变成:
public enum PaymentTermEnum { // 其他 OTHER("0") { @Override public List<PaymentPlan> resolve(ExecutionUnit unit) { ... } }, // 当月广告款次月5日结清 FIVE_DAY_NEXT_MONTH("1") { @Override public List<PaymentPlan> resolve(ExecutionUnit unit) { ... } }, // 每月30日前向乙方支付上月广告款. BEFORE_END_MONTH_PAY_PREVIEW_MONTH("2") { @Override public List<PaymentPlan> resolve(ExecutionUnit executionUnit) { ... } }, ... ; // 解析付款计划 public abstract List<PaymentPlan> resolve(ExecutionUnit executionUnit); private String value; private static ExecutionUnitService executionUnitService = ApplicationContextUtil.getContext().getBean( ExecutionUnitService.class); private static ContractService contractService = ApplicationContextUtil.getContext().getBean(ContractService.class); private static PaymentPlanService paymentPlanService = ApplicationContextUtil.getContext().getBean( PaymentPlanService.class); private static Map<String, PaymentTermEnum> valueMap = new HashMap<String, PaymentTermEnum>(); static { for (PaymentTermEnum paymentTermEnum : PaymentTermEnum.values()) { valueMap.put(paymentTermEnum.value, paymentTermEnum); } } public static PaymentTermEnum fromValue(String value) { return valueMap.get(value); } private PaymentTermEnum(String value) { this.value = value; } public String getValue() { return this.value; } }
?解析的Service类的方法就可以简化成:
public List<PaymentPlan> resolve(ExecutionUnit unit, String paymentTermsNumber) { PaymentTermEnum paymentTermEnum = PaymentTermEnum.fromValue(paymentTermsNumber); if (paymentTermEnum != null) { return paymentTermEnum.resolve(unit); } return new ArrayList<PaymentPlan>(); }
?当要添加解析策略的时候,只需要在枚举类中添加一个新的常量即可,而此时编译器会强制我们实现resolve方法,还想假装疏忽没注意,嘿嘿妈妈都不同意。
?