重构手法——代码健壮性增强类|代码洁癖治理|分解条件

简介

"分解条件"(Decompose Conditional)是一种重构手法,当条件逻辑较为复杂时,将条件判断和对应的操作分别提取到独立的方法中,能使代码结构更清晰,提高代码的可读性和可维护性。复杂的条件逻辑会让代码变得难以理解和修改,通过分解条件,可以将复杂的逻辑拆分成多个简单的逻辑片段。

针对的症状(代码坏味道)

  • 复杂的条件语句:条件判断中包含多个逻辑运算符(如 &&||),导致条件表达式冗长复杂。
  • 条件语句内的逻辑复杂:ifelseelse if 分支内包含大量代码,使代码的意图不明确。

分解条件(Decompose Conditional)的详细步骤

  1. 识别复杂条件逻辑
    • 寻找长条件表达式:在代码中找到包含多个逻辑运算符的条件判断语句。
    • 确认分支逻辑复杂:检查 ifelseelse if 分支内的代码是否包含较多的逻辑操作。
  2. 提取条件判断
    • 创建独立方法:为每个条件判断创建一个独立的方法,方法名应能清晰描述该条件的含义。
    • 移动条件表达式:将条件表达式复制到新方法中,并返回布尔值。
  3. 提取分支逻辑
    • 创建独立方法:为每个 ifelseelse if 分支内的代码创建独立的方法,方法名应能清晰描述该分支的操作。
    • 移动分支代码:将分支内的代码复制到新方法中。
  4. 替换原始代码
    • 调用新方法:在原始的条件语句中,用调用新方法的语句替换条件表达式和分支代码。
  5. 测试
    • 编译代码:确保代码编译通过,没有任何语法错误。
    • 运行测试:运行所有相关的单元测试,确保重构操作没有引入新的错误。
    • 手动测试:如果有必要,进行手动测试以验证功能的正确性。
  6. 代码审查
    • 同行评审:让同事或其他团队成员审查你的更改,确保代码质量和可维护性没有下降。
    • 文档更新:如果项目有维护文档的习惯,记得更新相关文档,说明分解条件的影响。

示例

假设有一个方法根据日期判断是否为夏季促销时间,并进行相应的价格计算。

原始代码

java 复制代码
import java.util.Calendar;

public class PriceCalculator {
    private double basePrice;

    public PriceCalculator(double basePrice) {
        this.basePrice = basePrice;
    }

    public double calculatePrice() {
        Calendar calendar = Calendar.getInstance();
        int month = calendar.get(Calendar.MONTH);
        if (month >= Calendar.JUNE && month <= Calendar.AUGUST) {
            return basePrice * 0.8; // 夏季促销,八折
        } else {
            return basePrice;
        }
    }
}

重构步骤

  1. 识别复杂条件逻辑:条件判断 month >= Calendar.JUNE && month <= Calendar.AUGUST 用于判断是否为夏季。
  2. 提取条件判断:
    • 创建独立方法:创建 isSummer 方法。
    • 移动条件表达式:将条件表达式复制到 isSummer 方法中。
  3. 提取分支逻辑:
    • 创建独立方法:分别创建 calculateSummerPricecalculateNormalPrice 方法。
    • 移动分支代码:将分支内的代码复制到相应的新方法中。
  4. 替换原始代码:
    • 调用新方法:在 calculatePrice 方法中调用新方法。

重构后代码

java 复制代码
import java.util.Calendar;

public class PriceCalculator {
    private double basePrice;

    public PriceCalculator(double basePrice) {
        this.basePrice = basePrice;
    }

    public double calculatePrice() {
        if (isSummer()) {
            return calculateSummerPrice();
        } else {
            return calculateNormalPrice();
        }
    }

    private boolean isSummer() {
        Calendar calendar = Calendar.getInstance();
        int month = calendar.get(Calendar.MONTH);
        return month >= Calendar.JUNE && month <= Calendar.AUGUST;
    }

    private double calculateSummerPrice() {
        return basePrice * 0.8;
    }

    private double calculateNormalPrice() {
        return basePrice;
    }
}

练习

基础练习题

  1. 简单条件分解

    • 给定以下 Java 代码,根据用户年龄判断是否可以购买酒精饮料。请分解条件逻辑。

      java 复制代码
        public class AlcoholPurchaseChecker {
            public boolean canPurchaseAlcohol(int age) {
                if (age >= 21) {
                    return true;
                } else {
                    return false;
                }
            }
        }
  2. 多分支条件分解

    • 下面的 Java 代码根据学生的考试成绩给出不同的评价。请分解条件逻辑。

      java 复制代码
        public class GradeEvaluator {
            public String evaluateGrade(int score) {
                if (score >= 90) {
                    return "Excellent";
                } else if (score >= 80) {
                    return "Good";
                } else if (score >= 70) {
                    return "Average";
                } else {
                    return "Needs Improvement";
                }
            }
        }

进阶练习题

  1. 复杂条件分解与参数传递

    • 在这段 Java 代码中,根据用户的会员等级、消费金额和购买时间判断是否可以享受折扣。请分解条件逻辑,并正确处理参数传递。

      java 复制代码
        import java.util.Calendar;
      
      public class DiscountChecker {
          public boolean canGetDiscount(String membershipLevel, double totalSpent, Calendar purchaseTime) {
              int month = purchaseTime.get(Calendar.MONTH);
              if ((membershipLevel.equals("premium") && totalSpent > 500) || (month >= Calendar.DECEMBER && month <= Calendar.FEBRUARY)) {
                  return true;
              } else {
                  return false;
              }
          }
      }
  2. 条件分解与返回值处理

    • 给定以下 Java 代码,根据订单状态和库存数量进行不同的处理。请分解条件逻辑,并确保返回值正确处理。

      java 复制代码
        public class OrderProcessor {
            public String processOrder(String orderStatus, int inventory) {
                if (orderStatus.equals("pending") && inventory > 0) {
                    return "Process order";
                } else if (orderStatus.equals("cancelled")) {
                    return "Cancel order";
                } else {
                    return "Hold order";
                }
            }
        }

综合拓展练习题

  1. 多模块条件分解与代码审查模拟
    • 考虑一个简单的 Java 游戏系统,有玩家类 Player,在玩家攻击怪物时,根据玩家的等级、武器类型和怪物的防御状态判断攻击是否有效。同时,根据玩家的体力值和技能冷却时间判断是否可以使用技能。请对这些条件逻辑进行 "分解条件" 重构。

    • 假设你完成了重构,请模拟一份简单的代码审查报告,指出重构后的优点和可能存在的潜在问题。

      java 复制代码
        public class Player {
            private int level;
            private String weaponType;
            private int stamina;
            private boolean skillOnCooldown;
      
            public Player(int level, String weaponType, int stamina, boolean skillOnCooldown) {
                this.level = level;
                this.weaponType = weaponType;
                this.stamina = stamina;
                this.skillOnCooldown = skillOnCooldown;
            }
      
            public boolean attackMonster(int monsterDefense) {
                if ((level >= 10 && weaponType.equals("sword")) || (monsterDefense < 20)) {
                    return true;
                } else {
                    return false;
                }
            }
      
            public boolean useSkill() {
                if (stamina > 50 && !skillOnCooldown) {
                    return true;
                } else {
                    return false;
                }
            }
        }
相关推荐
追逐时光者9 分钟前
面试官问:你知道 C# 单例模式有哪几种常用的实现方式?
后端·.net
Asthenia041227 分钟前
Numpy:数组生成/modf/sum/输出格式规则
后端
Asthenia041237 分钟前
NumPy:数组加法/数组比较/数组重塑/数组切片
后端
Asthenia041243 分钟前
Numpy:limspace/arange/数组基本属性分析
后端
Asthenia04121 小时前
Java中线程暂停的分析与JVM和Linux的协作流程
后端
Asthenia04121 小时前
Seata TCC 模式:RootContext与TCC专属的BusinessActionContext与TCC注解详解
后端
自珍JAVA1 小时前
【代码】zip压缩文件密码暴力破解
后端
今夜有雨.1 小时前
HTTP---基础知识
服务器·网络·后端·网络协议·学习·tcp/ip·http
Asthenia04121 小时前
Seata TCC 模式的空回滚与悬挂问题之解决方案-结合时序分析
后端
Asthenia04122 小时前
分析TCC分布式事务的问题:空回滚与悬挂
后端