问题描述:在创建合同时,会选择一个何时付款的策略,比如,目前策略有:
合同执行开始时付款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方法,还想假装疏忽没注意,嘿嘿妈妈都不同意。
相关推荐
Java语言为重构提供了良好的支持,书中探讨了如何利用Java的接口、抽象类、匿名内部类以及枚举类型等特性来进行有效的重构。例如,利用接口可以提供不同实现,提高程序的灵活性;抽象类则有助于定义通用的基础行为。...
4. **c#重构**:c#重构技巧包括提取方法、提取类、替换魔术字符串为常量或枚举,以及利用泛型和接口来提高代码的复用性和解耦。 5. **java重构**:在Java环境中,重构可能涉及重构设计模式,如单例模式、工厂模式,...
他建议开发者应该利用自动化测试框架来验证重构后的代码,确保重构不会引入新的错误。此外,良好的设计原则如单一职责原则(SRP)、开闭原则(OCP)和依赖倒置原则(DIP)是指导重构工作的重要准则,这些原则有助于...
读者可以通过这个例子更好地理解重构的实际操作,包括如何使用版本控制工具跟踪每一步变化,以及如何利用IDE的重构工具来辅助这一过程。 总的来说,重构是一个系统性的、持续的过程,需要开发者具备扎实的编程基础...
在.NET平台上,我们可以利用各种工具和库来支持重构工作。例如,Visual Studio 提供了内置的重构功能,如提取方法、提取接口、重命名变量等,使得代码修改变得更加便捷。此外,.NET Framework提供的强大类库和设计...
11. **使用TDD(Test-Driven Development)**:在重构过程中,测试驱动开发是一种强大的工具,先写测试再重构代码,确保重构过程不会破坏原有功能。 12. **代码审查**:重构后的代码应经过同行评审,以确保改进符合...
将常量定义为具有明确含义的变量或枚举,提高代码可读性并避免错误。 ### 使用断言、异常确保实现的正确性 断言用于在开发阶段检查代码的正确性,异常则用于捕获和处理运行时错误,两者结合能有效地确保程序的健壮...
Swift项目模板,作为一款专为...通过深入研究和应用其中的封装、优化、复用和重构策略,你将能够编写出更加健壮、高效且易于维护的Swift代码。无论是初学者还是经验丰富的开发者,这个模板都能提供宝贵的指导和灵感。
12. **代码重构**:定期进行代码重构,以保持代码的整洁和可维护性,但要注意不要过度重构。 13. **枚举与常量**:使用枚举代替硬编码的整数值,使代码更具可读性和可维护性。 14. **静态类与实例类**:合理使用...
Layer子域名挖掘机4.1 重构版是一款专为网络安全专业人士设计的工具,它主要用于发现和枚举目标组织或网站的子域名。子域名挖掘在网络安全领域具有重要意义,因为这些子域名可能隐藏着未公开的服务器、服务或者敏感...
例如,使用`using`语句管理资源,避免使用枚举的`foreach`循环,以及利用缓存技术如Redis或MemoryCache减少数据库访问。 5. **设计模式应用**:.NET开发中常见的设计模式有工厂模式、单例模式、观察者模式等。正确...
C#到Java的转换工具通常会解析C#源代码,识别出语法规则,并按照Java的语法规则重构代码。这个过程中,工具需要处理的关键点包括但不限于: 1. 类和对象:C#中的类和接口转换为Java中的对应结构。 2. 方法:C#的...
- 使用配置文件或者枚举类来管理固定值,提高代码的灵活性和可维护性。 ### 7. 优化循环 - **减少循环内的计算**:尽可能将不依赖循环索引的计算移出循环体外。 - **提前退出循环**:当满足条件时立即返回结果,...
可以使用switch-case,枚举,或者策略模式来替代。例如,使用`Objects.requireNonNull(obj, "obj must not be null")`代替手动的null检查。 5. 将复杂逻辑分解:当一个方法包含太多逻辑时,尝试将其拆分为多个小型...
9. **替换类型码与案例语句**:用面向对象的方式替换传统的类型码和大量case语句,例如使用枚举类型或策略模式。 10. **使用工厂方法**:将对象创建过程封装在工厂方法中,使代码更易于扩展和测试。 这些重构实践...
替换魔法数字可以将其转换为常量或枚举,增强代码的可读性。 5. **使用工厂方法**:通过工厂方法,可以将对象的创建过程封装起来,使得代码更加灵活,易于扩展。 6. **引入参数对象**:当一个函数接收过多的参数时...
ArcGIS10的开发迁移不仅仅是简单的代码移植,它涉及到开发环境的全面升级、新特性的学习以及旧代码的重构。开发者在进行迁移时,需细致规划,逐步实施,确保新版本的应用程序能够充分利用ArcGIS10的功能,同时保持...
总的来说,将Boost.Voronoi移植到Rust是一项挑战性的任务,需要对两种语言都有深入的理解,并能够充分利用Rust的特性来优化和重构代码。完成这项工作不仅能够扩展Rust的算法库,也有助于开发者更好地理解和比较不同...
- **重构代码**:通过提取公共函数或类,将相似功能的实现集中管理。 - **使用设计模式**:例如工厂模式、策略模式等,可以帮助减少代码冗余。 - **自动化工具**:利用代码审查工具、静态分析工具等辅助发现并...