IntelliJ IDEA 重构 uMarkdown 实战:Rename / Extract Method 手法详解
IntelliJ IDEA 重构 uMarkdown 实战:Rename / Extract Method 手法详解
写在前面:这本 GitHub 重构指南在讲什么
《GitHub 漫游指南》中专门有一章讲「改善 GitHub 项目代码质量:重构」,用一个真实的开源小项目 uMarkdown(一个把 Markdown 转换成 HTML 的库)做重构示范,并手把手演示 IntelliJ IDEA 的 5 种经典重构手法:Rename、Extract Method、Inline Method、Pull Members Up、Replace Temp with Query。本章完整收录在 06-refactor-project.md。
为什么重构:写代码容易,读代码难
书里的一句话很扎心:
写代码容易,读代码难。
假设我们写代码只要半天,别人读起来却要一天。那为什么不花一天的时间把代码写得更好,让别人半天就能读懂?
两条铁律先记住:
- 没有测试保护,不要动已上线的代码——盲目重构只会引入更多 Bug;
- 重构要小步快跑:编写测试 → 功能代码 → 修改测试 → 重构,每个循环都跑一遍测试。
获取重构练习代码:uMarkdown 长什么样
uMarkdown 的代码是非常典型的「过程式代码」:一连串 while 循环里堆着正则匹配和字符串替换,比如处理 code 块的部分:
while ((stra = micromarkdown.regexobject.code.exec(str)) !== null) {
str = str.replace(stra[0], '<code>\n' + micromarkdown.htmlEncode(stra[1]) ...);
}
问题一目了然:
- 变量名
stra、str含义不明; - 每一段 while 循环结构几乎一模一样,大量重复;
- 所有逻辑挤在一个函数里,职责不清。
它的 Markdown 解析过程类似「Pipe and Filters」架构模式:正则表达式是各个 Filter,字符串 str 是管口的输入输出。重构目标,就是把这些 Filter 一个个抽出来。完整代码与说明见 06-refactor-project.md。
IntelliJ IDEA 重构手法一:Rename 重命名(Shift + F6)
作用:安全重命名。把光标放在变量名上,按下 Shift + F6,输入新名字,IDEA 会自动更新所有引用位置。
书中示例:变量 c、d 根本看不出表达什么,重命名为 result_add、result_sub 后,代码立刻可读:
int result_add = new Cal().add(1, 2);
int result_sub = new Cal2().sub(2, 1);
新手最常犯的错误是手动全局替换,漏改一处就埋下 bug;Rename 重构由编译器级分析保证引用一致,永远选它。
IntelliJ IDEA 重构手法二:Extract Method 提取方法(Alt + Cmd + M)
作用:把选中的代码片段提取成独立方法,让主流程更清晰。
书中对 uMarkdown 的重构正是从这里开始:把 code 块那段 while 循环体,提取成 codeFilter 方法:
codeFilter: function (str, stra) {
return str.replace(stra[0], '<code>\n' + micromarkdown.htmlEncode(stra[1]) ...);
}
原来的 while 循环就变成:
while ((stra = regexobject.code.exec(str)) !== null) {
str = this.codeFilter(str, stra);
}
对 mail、headline 做同样处理后,再用 forEach + apply 把重复循环统一掉——9 种 Markdown 类型的处理,从一坨重复代码变成三行。提取方法后记得跑一遍全部测试,看到 ✓ 全绿再提交。
IntelliJ IDEA 重构手法三:Inline Method 内联方法(Alt + Cmd + N)
作用:与提取方法相反,把过短、没有存在价值的方法「压回」调用处。
书中演示:如果刚提取的 mprint 方法只有一行 System.out.println,反而让阅读多一次跳转,那就选它执行 Inline,勾选「Inline all invocations and remove the method」,代码还原为直接调用。
提取与内联是一对来回:方法名能表达意图就保留,不能就内联回去。
IntelliJ IDEA 重构手法四:Pull Members Up 上提成员
作用:把子类里「本该属于父类」的成员上提到基类。
书中例子:Cal2 extends Cal,但 sub 方法写在子类 Cal2 里,而 add 在父类 Cal 里。右键选择 Pull Members Up,sub 被提到 Cal,两个方法归位,继承结构才符合直觉。
IntelliJ IDEA 重构手法五:Replace Temp with Query 以查询取代临时变量
作用:过多的临时变量会撑长函数。选中临时变量,执行该重构,它会被替换成一个查询方法,函数体只留逻辑主干。
重构前,basePrice 临时变量夹在判断中间:
public void count() {
double basePrice = _quantity * _itemPrice;
if (basePrice > 1000) {
return basePrice * 0.95;
} else {
return basePrice * 0.98;
}
}
重构后,函数主干只剩业务判断:
public void count() {
if (basePrice() > 1000) {
return basePrice() * 0.95;
} else {
return basePrice() * 0.98;
}
}
小技巧:它等价于先对表达式「Extract Method」再「Inline Method」两步走,记住这点,任何编辑器里都能手工复刻。
重构循环:测试先行,diff 收尾
把五种手法串起来,就是书中推荐的完整开发流程:
- 编写测试(功能复杂时先行,功能简单时可行);
- 写功能代码;
- 修改、补充测试;
- 重构,并随时运行测试。
每完成一个循环,用 diff 检查一遍改动范围——只看到预期的几行变化,才敢提交。
小结:一套 GitHub 代码重构技巧清单
| 手法 | 快捷键(Mac) | 一句话场景 |
|---|---|---|
| Rename | Shift + F6 | 变量名含义不明 |
| Extract Method | Alt + Cmd + M | 函数过长、逻辑可独立命名 |
| Inline Method | Alt + Cmd + N | 方法太短,反而碍阅读 |
| Pull Members Up | 右键 Refactor | 成员放错了子类 |
| Replace Temp with Query | Cmd + Alt + Shift + T | 临时变量撑长函数 |
重构不是「重写」,而是一系列安全、可回滚的小变形。想完整练习,可以到 Artisan Stack 的 js-refactor 练习仓库里动手,把 uMarkdown 的每个 Filter 都抽出来,跑绿全部测试后再提交 pull request。更多章节可阅读 GitHub 漫游指南。


