`
liuluo129
  • 浏览: 116297 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

利用策略枚举重构代码

阅读更多

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

    合同执行开始时付款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方法,还想假装疏忽没注意,嘿嘿妈妈都不同意。

 

0
2
分享到:
评论

相关推荐

    重构——提高现有代码的质量

    4. **c#重构**:c#重构技巧包括提取方法、提取类、替换魔术字符串为常量或枚举,以及利用泛型和接口来提高代码的复用性和解耦。 5. **java重构**:在Java环境中,重构可能涉及重构设计模式,如单例模式、工厂模式,...

    关于软件重构技术的ppt

    读者可以通过这个例子更好地理解重构的实际操作,包括如何使用版本控制工具跟踪每一步变化,以及如何利用IDE的重构工具来辅助这一过程。 总的来说,重构是一个系统性的、持续的过程,需要开发者具备扎实的编程基础...

    重构技术—经典实例【影片租赁系统】

    在.NET平台上,我们可以利用各种工具和库来支持重构工作。例如,Visual Studio 提供了内置的重构功能,如提取方法、提取接口、重命名变量等,使得代码修改变得更加便捷。此外,.NET Framework提供的强大类库和设计...

    重构

    11. **使用TDD(Test-Driven Development)**:在重构过程中,测试驱动开发是一种强大的工具,先写测试再重构代码,确保重构过程不会破坏原有功能。 12. **代码审查**:重构后的代码应经过同行评审,以确保改进符合...

    重构36计.docx

    将常量定义为具有明确含义的变量或枚举,提高代码可读性并避免错误。 ### 使用断言、异常确保实现的正确性 断言用于在开发阶段检查代码的正确性,异常则用于捕获和处理运行时错误,两者结合能有效地确保程序的健壮...

    Swift项目模板,代封装、优化、复用、重构试验场.zip

    Swift项目模板,作为一款专为...通过深入研究和应用其中的封装、优化、复用和重构策略,你将能够编写出更加健壮、高效且易于维护的Swift代码。无论是初学者还是经验丰富的开发者,这个模板都能提供宝贵的指导和灵感。

    改善C#的157个建议编写高质量代码.zip

    12. **代码重构**:定期进行代码重构,以保持代码的整洁和可维护性,但要注意不要过度重构。 13. **枚举与常量**:使用枚举代替硬编码的整数值,使代码更具可读性和可维护性。 14. **静态类与实例类**:合理使用...

    Layer子域名挖掘机4.1 重构版

    Layer子域名挖掘机4.1 重构版是一款专为网络安全专业人士设计的工具,它主要用于发现和枚举目标组织或网站的子域名。子域名挖掘在网络安全领域具有重要意义,因为这些子域名可能隐藏着未公开的服务器、服务或者敏感...

    .NET开发人员高度策略

    例如,使用`using`语句管理资源,避免使用枚举的`foreach`循环,以及利用缓存技术如Redis或MemoryCache减少数据库访问。 5. **设计模式应用**:.NET开发中常见的设计模式有工厂模式、单例模式、观察者模式等。正确...

    C#代码转java代码

    C#到Java的转换工具通常会解析C#源代码,识别出语法规则,并按照Java的语法规则重构代码。这个过程中,工具需要处理的关键点包括但不限于: 1. 类和对象:C#中的类和接口转换为Java中的对应结构。 2. 方法:C#的...

    JAVA优质代码编写的30条可行建议

    - 使用配置文件或者枚举类来管理固定值,提高代码的灵活性和可维护性。 ### 7. 优化循环 - **减少循环内的计算**:尽可能将不依赖循环索引的计算移出循环体外。 - **提前退出循环**:当满足条件时立即返回结果,...

    提升java代码简洁度的几个小技巧

    可以使用switch-case,枚举,或者策略模式来替代。例如,使用`Objects.requireNonNull(obj, "obj must not be null")`代替手动的null检查。 5. 将复杂逻辑分解:当一个方法包含太多逻辑时,尝试将其拆分为多个小型...

    fowler-refactoring:马丁·福勒(Martin Fowler)的《改进现有代码的设计》中的示例中的重构实践。 将作为实用测试提供给我的软件工程课

    9. **替换类型码与案例语句**:用面向对象的方式替换传统的类型码和大量case语句,例如使用枚举类型或策略模式。 10. **使用工厂方法**:将对象创建过程封装在工厂方法中,使代码更易于扩展和测试。 这些重构实践...

    《31Days Refactoring》英文版 附源码

    替换魔法数字可以将其转换为常量或枚举,增强代码的可读性。 5. **使用工厂方法**:通过工厂方法,可以将对象的创建过程封装起来,使得代码更加灵活,易于扩展。 6. **引入参数对象**:当一个函数接收过多的参数时...

    Boost voronoi 移植到rust_代码_下载

    总的来说,将Boost.Voronoi移植到Rust是一项挑战性的任务,需要对两种语言都有深入的理解,并能够充分利用Rust的特性来优化和重构代码。完成这项工作不仅能够扩展Rust的算法库,也有助于开发者更好地理解和比较不同...

    敏捷软件开发的必要技巧

    - **重构代码**:通过提取公共函数或类,将相似功能的实现集中管理。 - **使用设计模式**:例如工厂模式、策略模式等,可以帮助减少代码冗余。 - **自动化工具**:利用代码审查工具、静态分析工具等辅助发现并...

    The ultimate question of programming refactoring

    《编程重构终极问题》是一本关于软件重构过程中常见问题的书籍,它为程序员提供了在重构代码时应避免的错误和解决方案。该书不仅覆盖了基础的重构原则,还涉及到了一些高级的问题和解决方案,为程序员在实际工作中...

    Clean-Code-Study:TDD,重构,有效的Java,设计模式,框架

    其中的一些关键点包括:使用枚举代替常量类,避免使用原始类型,利用泛型提升代码复用,以及善用静态工厂方法而非公有构造器等。这些原则有助于写出更高效、更安全的Java程序。 **设计模式** 设计模式是软件工程中...

Global site tag (gtag.js) - Google Analytics