利用计策枚举重构代码

利用策略枚举重构代码问题描述:在创建合同时,会选择一个何时付款的策略,比如,目前策略有:? ? 合同执行开始

利用策略枚举重构代码

问题描述:在创建合同时,会选择一个何时付款的策略,比如,目前策略有:

? ? 合同执行开始时付款100%,

? ? 合同执行结束后付款100%

? ? 合同每月结算当月应付金额

? ? ...

?

并且付款的策略还会改变。

最初的代码使用一大串if...else...,如下:

 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方法,还想假装疏忽没注意,嘿嘿妈妈都不同意。

?