简介
"分解条件"(Decompose Conditional)是一种重构手法,当条件逻辑较为复杂时,将条件判断和对应的操作分别提取到独立的方法中,能使代码结构更清晰,提高代码的可读性和可维护性。复杂的条件逻辑会让代码变得难以理解和修改,通过分解条件,可以将复杂的逻辑拆分成多个简单的逻辑片段。
针对的症状(代码坏味道)
- 复杂的条件语句:条件判断中包含多个逻辑运算符(如
&&
、||
),导致条件表达式冗长复杂。 - 条件语句内的逻辑复杂:
if
、else
或else if
分支内包含大量代码,使代码的意图不明确。
分解条件(Decompose Conditional)的详细步骤
- 识别复杂条件逻辑
- 寻找长条件表达式:在代码中找到包含多个逻辑运算符的条件判断语句。
- 确认分支逻辑复杂:检查
if
、else
或else if
分支内的代码是否包含较多的逻辑操作。
- 提取条件判断
- 创建独立方法:为每个条件判断创建一个独立的方法,方法名应能清晰描述该条件的含义。
- 移动条件表达式:将条件表达式复制到新方法中,并返回布尔值。
- 提取分支逻辑
- 创建独立方法:为每个
if
、else
或else if
分支内的代码创建独立的方法,方法名应能清晰描述该分支的操作。 - 移动分支代码:将分支内的代码复制到新方法中。
- 创建独立方法:为每个
- 替换原始代码
- 调用新方法:在原始的条件语句中,用调用新方法的语句替换条件表达式和分支代码。
- 测试
- 编译代码:确保代码编译通过,没有任何语法错误。
- 运行测试:运行所有相关的单元测试,确保重构操作没有引入新的错误。
- 手动测试:如果有必要,进行手动测试以验证功能的正确性。
- 代码审查
- 同行评审:让同事或其他团队成员审查你的更改,确保代码质量和可维护性没有下降。
- 文档更新:如果项目有维护文档的习惯,记得更新相关文档,说明分解条件的影响。
示例
假设有一个方法根据日期判断是否为夏季促销时间,并进行相应的价格计算。
原始代码
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;
}
}
}
重构步骤
- 识别复杂条件逻辑:条件判断
month >= Calendar.JUNE && month <= Calendar.AUGUST
用于判断是否为夏季。 - 提取条件判断:
- 创建独立方法:创建
isSummer
方法。 - 移动条件表达式:将条件表达式复制到
isSummer
方法中。
- 创建独立方法:创建
- 提取分支逻辑:
- 创建独立方法:分别创建
calculateSummerPrice
和calculateNormalPrice
方法。 - 移动分支代码:将分支内的代码复制到相应的新方法中。
- 创建独立方法:分别创建
- 替换原始代码:
- 调用新方法:在
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;
}
}
练习
基础练习题
-
简单条件分解
-
给定以下 Java 代码,根据用户年龄判断是否可以购买酒精饮料。请分解条件逻辑。
javapublic class AlcoholPurchaseChecker { public boolean canPurchaseAlcohol(int age) { if (age >= 21) { return true; } else { return false; } } }
-
-
多分支条件分解
-
下面的 Java 代码根据学生的考试成绩给出不同的评价。请分解条件逻辑。
javapublic 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"; } } }
-
进阶练习题
-
复杂条件分解与参数传递
-
在这段 Java 代码中,根据用户的会员等级、消费金额和购买时间判断是否可以享受折扣。请分解条件逻辑,并正确处理参数传递。
javaimport 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; } } }
-
-
条件分解与返回值处理
-
给定以下 Java 代码,根据订单状态和库存数量进行不同的处理。请分解条件逻辑,并确保返回值正确处理。
javapublic 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"; } } }
-
综合拓展练习题
- 多模块条件分解与代码审查模拟
-
考虑一个简单的 Java 游戏系统,有玩家类
Player
,在玩家攻击怪物时,根据玩家的等级、武器类型和怪物的防御状态判断攻击是否有效。同时,根据玩家的体力值和技能冷却时间判断是否可以使用技能。请对这些条件逻辑进行 "分解条件" 重构。 -
假设你完成了重构,请模拟一份简单的代码审查报告,指出重构后的优点和可能存在的潜在问题。
javapublic 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; } } }
-