重构手法千变万化,如果你看过《重构_改善既有代码的设计》这本书一定会很有感触,此文我从这本书中挑选个人觉得比较有用的几点,一些我在工作中觉得比较实用的重构手法。
(01) - 方法提炼
有句话叫,当你为了给一段代码写注释的时候,你就能考虑把他提炼一下了。
来看一个实际例子,登录
配合idea的Refactor->Extract->Method
原始代码如下:
其中2和3.1提炼到了private方法, 3提炼到了别的类里,因为明显这是个公共方法
来看一个实际例子,登录
配合idea的Refactor->Extract->Method
原始代码如下:
01.
public
String login()
02.
{
03.
//错误信息
04.
String error =
""
;
05.
//1 显示验证码框
06.
flag =
"1"
;
07.
//2 检查用户名密码为空
08.
returnInfoBean =
new
ReturnInfoBean();
09.
if
(StringUtils.isBlank(custId))
10.
{
11.
error =
"用户名不能为空"
;
12.
}
13.
else
if
(StringUtils.isBlank(custPassword))
14.
{
15.
error =
"登录密码不能为空"
;
16.
}
17.
if
(StringUtils.isNotBlank(error))
18.
{
19.
returnInfoBean.setSuccess(
false
);
20.
returnInfoBean.setReturnMessage(error);
21.
return
"login"
;
22.
}
23.
24.
try
25.
{
26.
//3 调用恒生登录
27.
HsDsApi hsApi =
new
HsDsApi(
";P 003"
,
"integrate/login"
, LOGGER);
28.
hsApi.put(
"logtype"
, logtype);
29.
hsApi.put(
"lognumber"
, custId);
30.
hsApi.put(
"password"
, custPassword);
31.
if
(StringUtils.isNotBlank(certificateType)) hsApi.put(
"certificatetype"
, certificateType);
32.
HsResponse respx = hsApi.callHsApi();
33.
returnInfoBean.setSuccess(respx.isSuccess());
34.
if
(respx.isSuccess())
35.
{
36.
//3.1 保存用户基本信息存入session
37.
String sessionKey = respx.getString(
"sessionkey"
);
38.
ICTLoginBean lb =
new
CTLoginBeanImpl();
39.
lb.setUserInfo(getUserInfo(sessionKey));
40.
lb.setAccountUtil(getAccountUtil(sessionKey));
41.
request.getSession().setAttribute(ICTLoginBean.sessionID, lb);
42.
}
43.
else
44.
{
45.
//3.2 登陆失败返回错误代码并处理
46.
throw
new
RuntimeException(
"【"
+ respx.getCode() +
"】"
+ respx.getMessage());
47.
}
48.
}
catch
(Exception r)
49.
{
50.
//3.3 调用失败
51.
error =
"系统异常,请稍候再试"
;
52.
LOGGER.error(
"调用恒生登录失败"
, r);
53.
}
54.
55.
//4 是否登陆成功
56.
if
(StringUtils.isNotBlank(error))
57.
{
58.
returnInfoBean.setSuccess(
false
);
59.
returnInfoBean.setReturnMessage(error);
60.
return
"login"
;
61.
}
62.
else
63.
{
64.
return
"first"
;
65.
}
66.
}
01.
public
String login()
02.
{
03.
returnInfoBean =
new
ReturnInfoBean();
04.
returnInfoBean.setSuccess(
true
);
05.
//1 显示验证码框
06.
flag =
"1"
;
07.
08.
//2 检查用户名密码为空
09.
if
(!checkLogin())
return
"login"
;
10.
11.
try
12.
{
13.
//3 调用恒生登录
14.
HsResponse respx = HsCommonAPi.login(logtype, custId, custPassword, certificateType);
15.
if
(respx.isSuccess())
16.
{
17.
//3.1 保存用户基本信息存入session
18.
saveInfoToSession(respx.getString(
"sessionkey"
));
19.
}
20.
else
21.
{
22.
//3.2 登陆失败返回错误代码并处理
23.
throw
new
RuntimeException(
"【"
+ respx.getCode() +
"】"
+ respx.getMessage());
24.
}
25.
}
26.
catch
(Exception r)
27.
{
28.
//3.3 调用失败
29.
returnInfoBean.setSuccess(
false
);
30.
returnInfoBean.setReturnMessage(
"系统异常,请稍候再试"
);
31.
LOGGER.error(
"调用恒生登录失败"
, r);
32.
}
33.
34.
//4 是否登陆成功
35.
return
returnInfoBean.isSuccess()?
"first"
:
"login"
;
36.
}
(02) - 分解临时变量
一个变量变用在多个地方,而且每次使用含义都不同,这个时候可以考虑把他分解
重构后
重构后
(03) - 以查询取代临时变量
如果一个临时变量在方法里赋值有点复杂,而且可能还会被复用。可以提炼到方法里可以说是第1话的子范例
重构后
重构后
(04) - 引入解释性变量
不解释自己看例子,目的为了代码有更好地可读性
重构后
重构后
(05) - 使代码更简洁
这部分功能,欢迎大家投稿
重构后
1.
if
( flag ==
1
){
2.
return
true
;
3.
}
4.
else
{
5.
return
false
;
6.
}
1.
return
flag ==
1
;
(06) - 尽早结束非正常逻辑
1.
if
(taskList !=
null
&& !taskList.isEmpty()){
2.
3.
//正常逻辑代码
4.
5.
return
count;
6.
}
1.
int
count =
0
;
2.
if
(taskList ==
null
|| taskList.isEmpty()){
3.
return
0
;
4.
}
5.
6.
//正常逻辑代码
7.
8.
return
count;
(07) - 满足条件立刻跳出循环
01.
public
boolean
contain(
int
year, Month month,
int
day) {
02.
boolean
found =
false
;
03.
for
(IPolyDate date : dateList) {
04.
if
(date.same(year, month.getMonth(), day)) {
05.
found =
true
;
06.
break
;
07.
}
08.
}
09.
10.
return
found;
11.
}
01.
public
boolean
contain(
int
year, Month month,
int
day) {
02.
for
(IPolyDate date : dateList) {
03.
if
(date.same(year, month.getMonth(), day)) {
04.
return
true
;
05.
}
06.
}
07.
08.
return
false
;
09.
}
(08) - 使用数据构分离公共逻辑,避免重复(坚持DRY原则)
DRY原则:
不要重复粘帖你自己的代码。Don't repeat yourself
重构后
01.
public
void
testGetIntPart()
throws
Exception {
02.
assertEquals(
"0"
, digitTransform.getIntPart(
"0.01"
);
03.
assertEquals(
"1"
, digitTransform.getIntPart(
"1.2"
);
04.
assertEquals(
"1234"
, digitTransform.getIntPart(
"1234"
);
05.
assertEquals(
"1"
, digitTransform.getIntPart(
"1.01"
);
06.
assertEquals(
"0"
, digitTransform.getIntPart(
"0.01"
);
07.
assertEquals(
"11111"
, digitTransform.getIntPart(
"11111"
);
08.
assertEquals(
"1000"
, digitTransform.getIntPart(
"1000.11"
);
09.
}
重构后
01.
public
void
testGetIntPart()
throws
Exception {
02.
String[][] cases =
new
String[][] { {
"0.01"
,
"0"
}, {
"1.2"
,
"1"
},
03.
{
"1234"
,
"1234"
}, {
"1.01"
,
"1"
}, {
"0"
,
"0"
},
04.
{
"11111"
,
"11111"
}, {
"1000.11"
,
"1000"
} };
05.
06.
for
(
int
i =
0
, len = cases.length; i < len; i++) {
07.
assertEquals(cases[
1
], digitTransform.getIntPart(cases[
0
]));
08.
}
09.
}