Java重构案例

wen java案例 4

本文目录导读:

Java重构案例

  1. 案例一:魔法数字与硬编码 → 枚举与常量
  2. 案例二:长方法 + 多层嵌套 → 卫语句 + 提取方法
  3. 案例三:重复代码 → 模板方法模式
  4. 案例四:上帝类 → 拆分类(单一职责)
  5. 案例五:过度使用 if-else 判断类型 → 策略模式 / 函数式接口
  6. 推荐的重构工具与辅助手段

下面从实际场景出发,为你整理了几类典型的 Java 重构案例,每个案例都包含“重构前”的问题分析和“重构后”的代码对比。

这些案例覆盖了工作中最常见的代码坏味道,可以直接参考落地。


魔法数字与硬编码 → 枚举与常量

问题分析
代码中散落着大量无意义的数字和字符串,可读性差,后期维护时极易出错。

重构前

public class OrderService {
    public double calculateDiscount(String userType, double amount) {
        double discount;
        if (userType.equals("VIP")) {
            discount = 0.8;
        } else if (userType.equals("NORMAL")) {
            discount = 0.95;
        } else {
            discount = 1.0;
        }
        return amount * discount;
    }
}

重构后

public enum UserType {
    VIP(0.8),
    NORMAL(0.95),
    GUEST(1.0);
    private final double discountRate;
    UserType(double discountRate) {
        this.discountRate = discountRate;
    }
    public double getDiscountRate() {
        return discountRate;
    }
}
public class OrderService {
    public double calculateDiscount(UserType userType, double amount) {
        return amount * userType.getDiscountRate();
    }
}

重构收益:消除了魔法值,类型安全,业务逻辑更加清晰。


长方法 + 多层嵌套 → 卫语句 + 提取方法

问题分析
方法过长,且有大量 if-else 嵌套,导致逻辑难以阅读和测试,这也是非常经典的Composed Method问题。

重构前

public double calculateSalary(Employee employee) {
    double salary = 0.0;
    if (employee != null) {
        if (employee.getType() == EmployeeType.FULL_TIME) {
            if (employee.getWorkDays() > 20) {
                salary = employee.getBaseSalary() * 1.2;
            } else {
                salary = employee.getBaseSalary() * 1.0;
            }
            // 其他 FULL_TIME 相关逻辑
        } else if (employee.getType() == EmployeeType.PART_TIME) {
            salary = employee.getHourlyRate() * employee.getWorkHours();
            if (salary < 500) {
                salary = 500;
            }
        }
    }
    return salary;
}

重构后

public double calculateSalary(Employee employee) {
    // 卫语句提前返回,处理异常情况
    if (employee == null) {
        throw new IllegalArgumentException("employee cannot be null");
    }
    // 重构后通过多态或枚举分派
    return employee.calculateSalary();
}

进一步优化(引入策略模式)

// Employee 抽象类或接口
public abstract class Employee {
    protected String name;
    // ...
    public abstract double calculateSalary();
}
public class FullTimeEmployee extends Employee {
    @Override
    public double calculateSalary() {
        double salary = getBaseSalary();
        if (getWorkDays() > 20) {
            salary *= 1.2;
        }
        return salary;
    }
}
public class PartTimeEmployee extends Employee {
    @Override
    public double calculateSalary() {
        return Math.max(getHourlyRate() * getWorkHours(), 500);
    }
}

重构收益:消除了嵌套,提升了可读性,且后续新增员工类型时无需修改原逻辑(开闭原则)。


重复代码 → 模板方法模式

问题分析
两个或多个方法流程结构相似,但是其中部分步骤的实现不同,大量复制粘贴会导致如果修改了一个,常常忘记修改另一个。

重构前

public class CsvReportGenerator {
    public void generate() {
        System.out.println("连接数据库");
        // 查询 订单数据(特定逻辑)
        System.out.println("查询订单数据");
        System.out.println("处理为CSV格式");
        System.out.println("保存文件: report.csv");
    }
}
public class ExcelReportGenerator {
    public void generate() {
        System.out.println("连接数据库");
        // 查询 库存数据(特定逻辑)
        System.out.println("查询库存数据");
        System.out.println("处理为Excel格式");
        System.out.println("保存文件: report.xlsx");
    }
}

重构后(模板方法)

public abstract class ReportGenerator {
    // 模板方法定义算法骨架
    public final void generate() {
        connectDatabase();
        queryData();
        formatData();
        saveFile();
    }
    protected void connectDatabase() {
        System.out.println("连接数据库");
    }
    // 抽象方法,由子类实现具体差异
    protected abstract void queryData();
    protected abstract void formatData();
    protected void saveFile() {
        System.out.println("保存文件");
    }
}

上帝类 → 拆分类(单一职责)

问题分析
一个类承担了过多的职责,比如既要做数据校验、又要做业务计算、还要做持久化和发送消息,导致类庞大且难以测试。

重构前

public class UserService {
    public void createUser(User user) {
        // 1. 参数校验
        if (user.getEmail() == null || !user.getEmail().contains("@")) {
            throw new IllegalArgumentException("Invalid email");
        }
        // 2. 密码加密
        user.setPassword(encrypt(user.getPassword()));
        // 3. 保存数据库
        userDao.save(user);
        // 4. 发送欢迎邮件
        sendWelcomeEmail(user);
    }
    private String encrypt(String raw) { ... }
    private void sendWelcomeEmail(User user) { ... }
}

重构后(拆分)

// 1. 负责校验
@Component
public class UserValidator {
    public void validate(User user) {
        if (user.getEmail() == null || !user.getEmail().contains("@")) {
            throw new IllegalArgumentException("Invalid email");
        }
    }
}
// 2. 负责密码加密
@Component
public class PasswordEncoder {
    public String encode(String raw) { ... }
}
// 3. 负责邮件通知
@Component
public class EmailService {
    public void sendWelcomeEmail(User user) { ... }
}
// 4. 业务编排 / 门面
@Service
public class UserService {
    private final UserValidator validator;
    private final PasswordEncoder encoder;
    private final UserRepository userRepository;
    private final EmailService emailService;
    public UserService(UserValidator validator, PasswordEncoder encoder,
                       UserRepository userRepository, EmailService emailService) {
        this.validator = validator;
        this.encoder = encoder;
        this.userRepository = userRepository;
        this.emailService = emailService;
    }
    public void createUser(User user) {
        validator.validate(user);
        user.setPassword(encoder.encode(user.getPassword()));
        userRepository.save(user);
        emailService.sendWelcomeEmail(user);
    }
}

重构收益:UserService 现在只负责编排,便于测试和 Mock,且每个新类都有明确的单一职责。


过度使用 if-else 判断类型 → 策略模式 / 函数式接口

问题分析
经常根据类型或状态来切换执行逻辑,使用大量 if-else,代码冗长且每次新增类型都需要改动原方法。

重构前

public class ShippingCostCalculator {
    public double calculateCost(ShippingType type, double weight) {
        if (type == ShippingType.STANDARD) {
            return weight * 1.5;
        } else if (type == ShippingType.EXPRESS) {
            return weight * 3.0 + 10;
        } else if (type == ShippingType.OVERNIGHT) {
            return weight * 5.0 + 20;
        }
        throw new IllegalArgumentException("Unknown type");
    }
}

重构后(策略模式)

@FunctionalInterface
public interface ShippingStrategy {
    double calculate(double weight);
}
public class ShippingCostCalculator {
    private final Map<ShippingType, ShippingStrategy> strategies = new EnumMap<>(ShippingType.class);
    public ShippingCostCalculator() {
        strategies.put(ShippingType.STANDARD, w -> w * 1.5);
        strategies.put(ShippingType.EXPRESS, w -> w * 3.0 + 10);
        strategies.put(ShippingType.OVERNIGHT, w -> w * 5.0 + 20);
    }
    public double calculateCost(ShippingType type, double weight) {
        return strategies.getOrDefault(type, 
                w -> { throw new IllegalArgumentException("Unknown type"); })
                .calculate(weight);
    }
}

重构收益:消除了 if-else 链,新增策略时只需添加 Map 项或在外部注册,避免了侵入性修改,更加灵活。


推荐的重构工具与辅助手段

工具/手段 作用
IDE 重构快捷键(IntelliJ IDEA) 提取方法、引入常量、移动类等自动重构
SonarQube / SpotBugs 静态扫描,发现代码坏味道
单元测试 重构前后确保逻辑不变(安全网)
ArchUnit 架构层面约束依赖关系,防止循环依赖

抱歉,评论功能暂时关闭!