解决24种代码坏味道(1)

1.神秘命名
如果想不出一个好的名字,说明背后很可能隐藏着更深的设计问题
看最新的《阿里开发规范1.7 黄山版》
https://developer.aliyun.com/article/888697

2.重复代码
优化:禁止复制粘贴,巧用Method Exact。
1692107737850
坏味道

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
* 计算水果总价(同一个类的两个函数含有相同的表达式)
*
*/
public class FruitsCost {
public double computeMoneyWithoutPrivileges(String type, int numbers) {
double prices;
switch (type) {
case "apple":
prices = 5.5;
break;
case "banana":
prices = 4.0;
break;
case "strawberry":
prices = 10.5;
break;
default:
throw new IllegalArgumentException("Illegal type : " + type);
}
return prices * numbers;
}

public double computeMoneyWithPrivileges(String type, double numbers, double discount) {
double prices;
switch (type) {
case "apple":
prices = 5.5;
break;
case "banana":
prices = 4.0;
break;
case "strawberry":
prices = 10.5;
break;
default:
throw new IllegalArgumentException("Illegal type : " + type);
}
return prices * numbers * discount;
}
}

好味道

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
public class FruitsCost {
public double computeMoneyWithoutPrivileges(String type, int numbers) {
double prices = getPrices(type);
return prices * numbers;
}
private double getPrices(String type) {
double prices;
switch (type) {
case "apple":
prices = 5.5;
break;
case "banana":
prices = 4.0;
break;
case "strawberry":
prices = 10.5;
break;
default:
throw new IllegalArgumentException("Illegal type : " + type);
}
return prices;
}
public double computeMoneyWithPrivileges(String type, double numbers, double discount) {
double prices = getPrices(type);
return prices * numbers * discount;
}
}

3.过长函数
优化:每个函数建议不超过80行代码,条件、循环、公共集中的过程提取处理
坏味道

1
2
3
4
5
6
7
public void doSth3(){
List<String> list = new ArrayList<>();
for(String sjs : list){
//doSth,60行
sjs = sjs + "";
}
}

好味道

1
2
3
4
5
6
7
8
9
10
public void doSth3(){
List<String> list = new ArrayList<>();
for(String sjs : list){
doloop(sjs);
}
}
private static void doloop(String sjs) {
//doSth,60行
sjs = sjs + "";
}

4.过长参数列表
优化:使用对象合并参数
坏味道

1
2
3
4
5
public class Case2 {
public void createUser(String username,String password , Float height , Float weight,Integer age){

}
}

好味道

1
2
3
4
5
6
7
8
9
10
11
好味道
public class Case2 {
public void createUser(User user){

}
}
public class User {
private String username
private String password;
//...Getter and Setter
}

5.全局数据
优化:合并数据到方法、类成员中,最小范围原则
坏味道
代码问题

代码影响
好味道
封装变量

6.可变数据
优化:函数式编程、数据永不改变
什么是可变数据(Mutable Data)
定义:可变数据——对数据的修改经常导致出乎意料的结果和难以发现的Bug。

影响:影响可维护性,在一处修改数据,却在另一处造成难以发现的破坏

改进目标:应用“数据不可变”:不可变性是强大的代码防腐剂

方法:封装变量、拆分变量、提炼函数、移除设值函数、查询取代派生、Builder模式创建不可变对象、引用对象改为值对象、函数式编程等

注:并非所有可变类型都是不良的,这里关注描述数据的可变类型

坏味道
可变数据1
好味道
可变数据2
可变数据3

可变数据症状
一个变量用作不同目的
数据类型中,用public修饰非final成员
有set方法(或其它改变数据的方法)
一个成员变量的值可通过其他字段计算得到
对外暴露内部变量的可变引用

改进手法
封装变量
拆分变量(用提取函数):Ctrl+Atl+M
移除设值函数:用内联移除、直接删除(Ctrl+Alt+N、Alt+Del)
Builder模式创建不可变对象