改善既有代码的设计之重构技巧!

提炼函数(Extract Function)

提炼函数(Extract Function)是一种重构技术

  • 它的目的是将一个大的函数拆分成若干个小的、功能单一的函数。

这样做可以提高代码的可读性、可维护性,并且可以复用那些小的函数。

假设我们有一个函数,它的任务是为一个在线商店的用户创建一个账户,并发送一封欢迎邮件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class AccountService {
public void createAccount(String email, String username, String pwd) {
if (email == null || email.isEmpty()) {
throw new IllegalArgumentException("Email cannot be empty.");
}
if (username == null || username.isEmpty()) {
throw new IllegalArgumentException("Username cannot be empty.");
}
if (pwd == null || pwd.isEmpty()) {
throw new IllegalArgumentException("pwd cannot be empty.");
}

// 在这里插入数据库操作代码,创建账户

// 发送欢迎邮件
String welcomeMessage="Dear " + username + ", welcome to our service!";
// 在这里插入邮件发送代码
}
}

在这段代码中,createAccount方法同时负责验证输入、创建账户和发送邮件。

我们可以通过提炼函数来拆分这个方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class AccountService {
public void createAccount(String email, String username, String pwd) {
validateAccountDetails(email, username, pwd);
insertAccountIntoDatabase(email, username, pwd);
sendWelcomeEmail(username);
}

private void validateAccountDetails(String email, String username, String pwd) {
if (email == null || email.isEmpty()) {
throw new IllegalArgumentException("Email cannot be empty.");
}
if (username == null || username.isEmpty()) {
throw new IllegalArgumentException("Username cannot be empty.");
}
if (pwd == null || pwd.isEmpty()) {
throw new IllegalArgumentException("pwd cannot be empty.");
}
}

private void insertAccountIntoDatabase(String email, String username, String password) {
// 在这里插入数据库操作代码,创建账户
}

private void sendWelcomeEmail(String username) {
String welcomeMessage="Dear " + username + ", welcome to our service!";
// 在这里插入邮件发送代码
}
}

内联函数(Inline Function

内联函数(Inline Function)是一种重构技术

  • 用于将一个函数的内容移动到该函数被调用的地方,然后移除原函数。

这种技术通常用于当一个函数的体积非常小,而且只被使用一次或者函数的内容几乎和它的名字一样清晰时。

我们通过一个例子来说明内联函数的重构过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class LogisticsService {
public double processOrder(Order order) {
// 其他处理逻辑...
doubleshippingCost= calculateShippingCost(order);
// 其他处理逻辑...
return shippingCost;
}

private double calculateShippingCost(Order order) {
return getBaseShippingCost(order);
}

private double getBaseShippingCost(Order order) {
doublebaseCost=0.0;

return baseCost;
}
}

重构后的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class LogisticsService {
public double processOrder(Order order) {
// 其他处理逻辑...
double shippingCost= getBaseShippingCost(order);
// 其他处理逻辑...
return shippingCost;
}

private double getBaseShippingCost(Order order) {
double baseCost=0.0;

return baseCost;
}
}

提炼变量(Extract Variable)

将表达式的结果赋给一个临时变量,以提高表达式的清晰度。

1
2
3
if (order.getTotalPrice() - order.getDiscounts() > 100) {
// 逻辑处理
}

重构后:

1
2
3
4
doublenetPrice= order.getTotalPrice() - order.getDiscounts();
if (netPrice > 100) {
// 逻辑处理
}

内联变量(Inline Variable)

如果一个临时变量只被赋值一次,然后被直接使用,可以将其替换为直接使用赋值表达式。

1
2
doublebasePrice= order.basePrice();
return (basePrice > 1000);

重构后:

1
return order.basePrice() > 1000;

分解条件表达式(Decompose Conditional)

将复杂的条件逻辑分解为更清晰的逻辑块,提高其可读性。

1
2
3
4
5
public void applyFee(Account account) {
if (account.getBalance() < 0 && account.isOverdraftEnabled()) {
account.addFee(OVERDRAFT_FEE);
}
}

重构后:

1
2
3
4
5
6
7
8
public void applyFee(Account account) {
if (shouldApplyOverdraftFee(account)) {
account.addFee(OVERDRAFT_FEE);
}
}
private boolean shouldApplyOverdraftFee(Account account) {
return account.getBalance() < 0 && account.isOverdraftEnabled();
}

合并条件表达式(Consolidate Conditional Expression)

将多个条件表达式合并为一个,简化逻辑判断。

1
2
3
4
5
if (isSpecialDeal()) {
total = price * 0.95;
} else {
total = price * 0.98;
}

重构后:

1
total = price * (isSpecialDeal() ? 0.95 : 0.98);

移除死代码(Remove Dead Code)

删除不再被使用的代码,减少维护负担。

重构切量验证完成后,确保老代码无用,可直接删除主赠老逻辑calcTransferTimeForGift方法以及下面依赖的方法

  • 前提是这些方法没有其他地方依赖使用。