Java代码重构的实现方法
代码重构是改善既有代码设计而不改变其外部行为的过程,以下是具体的实现方法和案例:

重构的基本原则
- 小步修改:每次只做小的改动
- 测试保障:重构前必须有充分的测试
- 不改变功能:保持外部行为不变
常见重构案例及实现
提取方法(Extract Method)
重构前:
public void printOwing(String name) {
double outstanding = 0.0;
// 打印标题
System.out.println("*************************");
System.out.println("***** Customer Owes *****");
System.out.println("*************************");
// 计算欠款
Enumeration e = orders.elements();
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
outstanding += each.getAmount();
}
// 打印详细信息
System.out.println("name: " + name);
System.out.println("amount: " + outstanding);
}
重构后:
public void printOwing(String name) {
printBanner();
double outstanding = getOutstanding();
printDetails(name, outstanding);
}
private void printBanner() {
System.out.println("*************************");
System.out.println("***** Customer Owes *****");
System.out.println("*************************");
}
private double getOutstanding() {
double result = 0.0;
Enumeration e = orders.elements();
while (e.hasMoreElements()) {
Order each = (Order) e.nextElement();
result += each.getAmount();
}
return result;
}
private void printDetails(String name, double outstanding) {
System.out.println("name: " + name);
System.out.println("amount: " + outstanding);
}
提取类(Extract Class)
重构前:
public class Person {
private String name;
private String officeAreaCode;
private String officeNumber;
public String getTelephoneNumber() {
return "(" + officeAreaCode + ") " + officeNumber;
}
// getter/setter...
}
重构后:
public class Person {
private String name;
private TelephoneNumber officeTelephone = new TelephoneNumber();
public String getTelephoneNumber() {
return officeTelephone.getTelephoneNumber();
}
// getter/setter...
}
public class TelephoneNumber {
private String areaCode;
private String number;
public String getTelephoneNumber() {
return "(" + areaCode + ") " + number;
}
// getter/setter...
}
用多态替代条件表达式
重构前:
public double getSpeed() {
switch (_type) {
case EUROPEAN:
return getBaseSpeed();
case AFRICAN:
return getBaseSpeed() - getLoadFactor() * _numberOfCoconuts;
case NORWEGIAN_BLUE:
return (_isNailed) ? 0 : getBaseSpeed(_voltage);
}
throw new RuntimeException("Should be unreachable");
}
重构后:
abstract class Bird {
abstract double getSpeed();
}
class EuropeanSwallow extends Bird {
double getSpeed() {
return getBaseSpeed();
}
}
class AfricanSwallow extends Bird {
double getSpeed() {
return getBaseSpeed() - getLoadFactor() * _numberOfCoconuts;
}
}
class NorwegianBlueParrot extends Bird {
double getSpeed() {
return (_isNailed) ? 0 : getBaseSpeed(_voltage);
}
}
引入参数对象(Introduce Parameter Object)
重构前:
public void addDateRange(Date start, Date end) {
// ...
}
public boolean isInRange(Date start, Date end, Date date) {
// ...
}
重构后:
public class DateRange {
private final Date start;
private final Date end;
public DateRange(Date start, Date end) {
this.start = start;
this.end = end;
}
public boolean contains(Date date) {
return !date.before(start) && !date.after(end);
}
}
public void addDateRange(DateRange range) {
// ...
}
public boolean isInRange(DateRange range, Date date) {
return range.contains(date);
}
重构工具的使用
IDE内置重构功能
- IntelliJ IDEA:Ctrl+Alt+Shift+T(重构菜单)
- Eclipse:Alt+Shift+T(重构菜单)
- NetBeans:Ctrl+Shift+R(重构)
常用重构快捷操作
// 重命名类/方法/变量 // Shift+F6 (IntelliJ) / Alt+Shift+R (Eclipse) // 提取方法 // Ctrl+Alt+M (IntelliJ) / Alt+Shift+M (Eclipse) // 内联变量 // Ctrl+Alt+N (IntelliJ) // 移动成员 // F6 (IntelliJ)
重构策略和步骤
重构流程
graph TD
A[识别坏味道] --> B[编写测试]
B --> C[小步重构]
C --> D[运行测试]
D --> E{测试通过?}
E -->|是| F[提交代码]
E -->|否| G[回退修改]
G --> C
F --> H[继续下一个重构?]
H -->|是| A
H -->|否| I[结束]
代码坏味道识别清单
- 过长方法(Long Method)
- 过大类(Large Class)
- 重复代码(Duplicated Code)
- 过长参数列表(Long Parameter List)
- 发散式变化(Divergent Change)
- 霰弹式修改(Shotgun Surgery)
- 依恋情结(Feature Envy)
实际项目重构案例
电商订单处理系统重构
重构前(存在重复代码和过长方法):
public class OrderService {
public void processOrder(Order order) {
// 验证订单
if (order.getItems().isEmpty()) {
throw new IllegalArgumentException("Order has no items");
}
if (order.getCustomer() == null) {
throw new IllegalArgumentException("No customer");
}
if (!order.getCustomer().isValid()) {
throw new IllegalArgumentException("Customer invalid");
}
// 计算总额
double total = 0;
for (Item item : order.getItems()) {
total += item.getPrice() * item.getQuantity();
// 应用折扣
if (item.getCategory() == Category.ELECTRONICS) {
total *= 0.9;
} else if (item.getCategory() == Category.BOOKS) {
total *= 0.95;
}
}
// 发送邮件
EmailService.sendOrderConfirmation(order.getCustomer().getEmail(),
order.getId(), total);
}
}
重构后:
public class OrderService {
private final OrderValidator validator;
private final PriceCalculator priceCalculator;
private final NotificationService notificationService;
public OrderService() {
this.validator = new OrderValidator();
this.priceCalculator = new PriceCalculator();
this.notificationService = new EmailNotificationService();
}
public void processOrder(Order order) {
validator.validate(order);
double total = priceCalculator.calculateTotal(order);
notificationService.sendOrderConfirmation(order, total);
}
}
public class OrderValidator {
public void validate(Order order) {
validateItems(order);
validateCustomer(order.getCustomer());
}
private void validateItems(Order order) {
if (order.getItems().isEmpty()) {
throw new IllegalArgumentException("Order has no items");
}
}
private void validateCustomer(Customer customer) {
if (customer == null) {
throw new IllegalArgumentException("No customer");
}
if (!customer.isValid()) {
throw new IllegalArgumentException("Customer invalid");
}
}
}
public class PriceCalculator {
public double calculateTotal(Order order) {
double total = 0;
for (Item item : order.getItems()) {
total += calculateItemPrice(item);
}
return total;
}
private double calculateItemPrice(Item item) {
double price = item.getPrice() * item.getQuantity();
return applyDiscount(price, item.getCategory());
}
private double applyDiscount(double price, Category category) {
DiscountStrategy strategy = DiscountStrategyFactory.getStrategy(category);
return strategy.applyDiscount(price);
}
}
重构最佳实践
- 测试驱动重构:先写测试,再重构
- 持续集成:频繁提交,避免大规模改动
- 代码审查:团队协作进行重构审查
- 文档更新:重构后更新相关文档
- 性能考虑:避免过度重构影响性能
通过以上方法,可以系统化地进行Java代码重构,提升代码质量和可维护性。