重構是 IDE 給人類生活帶來便利的一個重要方面。但是 IDE 永遠不是我們肚子裡的蛔蟲,有時我們會有複雜到 IDE 不可能直接提供的重構需求。
下面我來告訴大家怎麼利用有限的 IDE 重構功能, 創造無限的價值 處理複雜的情況。
https://blog.didispace.com/intellij-idea-refactoring-skills/#%E5%A4%8D%E4%B9%A0%E4%B8%80%E4%B8%8B%E5%BF%AB%E6%8D%B7%E9%94%AE 複習一下快捷鍵
先複習一下快捷鍵吧,我們這次就看兩個就好。
https://blog.didispace.com/intellij-idea-refactoring-skills/#inline inline
這個叫
inline
的東西快捷鍵是 Ctrl+Alt+n。
這個東西的作用是把目前光标上的東西,在代碼級别内聯掉。
按下這個快捷鍵後,會看到一個彈窗(這個是
inline
一個 Kotlin 方法的彈窗,對于 Java 還多幾個選項。 不過這都不是重點啦):
我們都預設選第一個,就是在
inline
之後删除被
inline
的東西,第二個是
inline
後保留。
如果你是在調用處而不是定義處這麼搞,第三個選項就可以選,是隻
inline
這一處。
我們一般不管,使用第一個。
https://blog.didispace.com/intellij-idea-refactoring-skills/#rename rename
這個我就不多介紹了,應該是最常用的快捷鍵之一了: Shift+F6 。
https://blog.didispace.com/intellij-idea-refactoring-skills/#%E5%88%A0%E9%99%A4%E4%B8%80%E4%B8%AA%E8%A2%AB%E5%A4%9A%E6%AC%A1%E5%BC%95%E7%94%A8%E7%9A%84%E7%A9%BA%E5%87%BD%E6%95%B0 删除一個被多次引用的空函數
https://blog.didispace.com/intellij-idea-refactoring-skills/#%E5%9C%BA%E6%99%AF 場景
我們知道, IntelliJ 會把 “沒有被用到的函數” 标灰(這個 “沒有被用到” 的定義其實蠻複雜的,比如你實作了一個接口, 那麼這個接口的方法即使沒被調用也不會被标灰。這裡我就不糾結這個細節了),并且會給出 “Safe delete” 的提示。
這往往不是我們想要的,因為我們看到這個東西的時候, 多半都是剛寫完一個函數還沒來得及調用的時候。
而我們有時在重構的時候,一個函數裡面的東西被全部移出去後,這個函數體就是空的了,而它仍然在多處被調用。
我們這時想删除這個函數,以及它的所有調用處。
fun SymbolList.addGetSetFunction() {
}
比如這個,我在重構
Lice的時候,就産生了很多上面這種東西。
這個函數被調用了,是以 IntelliJ IDEA 不會給出 “Safe delete” 的選項。
雖然語言是 Kotlin ,但是這就是一個樸素的函數聲明,我覺得不需要進行進一步的說明。
private fun initialize() {
addDefines()
addGetSetFunction()
addControlFlowFunctions()
它像這樣被不停調用着。
當然,你可以按下 Ctrl 然後點選這個函數,再一處一處地删除。
https://blog.didispace.com/intellij-idea-refactoring-skills/#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95 解決方法
不過我們為什麼不試試直接
inline
掉它呢?
private fun initialize() {
addDefines()
addControlFlowFunctions()
它的函數體本身就是空的,是以說
inline
掉後,每個調用處就啥都沒了。
https://blog.didispace.com/intellij-idea-refactoring-skills/#%E4%BF%AE%E6%94%B9%E5%A4%A7%E9%87%8F%E5%87%BA%E7%8E%B0%E7%9A%84%E7%9B%B8%E5%90%8C%E7%BB%93%E6%9E%84 修改大量出現的相同結構
https://blog.didispace.com/intellij-idea-refactoring-skills/#%E5%9C%BA%E6%99%AF-1
比如,我們有這樣的,自己用的庫代碼(為了讓更多人看懂,我在這裡使用了 Java):
// code 0
class Val {
private Object o;
public Object getO() { return o; }
}
interface Node { Val eval(); }
然後我們可以通過
someNode.eval().getO()
來擷取一個
Object
,對吧。
然後想象一下我們有這樣的業務代碼:
// code 1
Object a = xxx.getNode().eval().getO();
xxx.use(yyy.eval().getO());
Val bla = blablabla.eval();
switch (bla.getO().toString()) {
case "2333":
break;
}
...
這是我們現在的代碼。
https://blog.didispace.com/intellij-idea-refactoring-skills/#%E9%97%AE%E9%A2%98 問題
然後我們經過一番小重構,把剛剛的庫代碼重構成了這樣:
// code 0
interface Node { Object eval(); }
直接把
Val
去掉了,然後讓這個
eval()
直接傳回原本裝在
Val
裡面的變量,然後
Node
的各種實作也都改了。
這時候我們的業務代碼已經是一坨紅色了。
我們想批量去掉這個
.getO()
的結構,應該怎麼辦呢?
首先我們不考慮查找替換,因為
- 有這種結構的檔案很多(假設有一萬個),很麻煩(不過 IntelliJ IDEA 有 “Replace in path” 功能)
- 有很多其他的叫
但不需要被重構掉的函數,會受到波及(這才是最主要的)getO()
這也是很常見的原因,對吧。
這時我們就需要技巧性地重構了。
https://blog.didispace.com/intellij-idea-refactoring-skills/#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95-1
首先,我們先把庫代碼中的
Node
臨時性地改成這個樣子(也就是說,臨時性地把
Val
弄回來,隻是實作變得不一樣了):
// code 0
class Val {
public Object getO() { return this; }
}
interface Node { Val eval(); }
注意這裡的
getO()
被改成了傳回
this
。
這時我們剛剛的代碼中,
.getO()
上的紅色已經消失了(畢竟這幾乎就是改之前的樣子)。
然後,我們對 public Object getO() { return this; } 中的 getO() 使用 inline, 這樣所有的
.getO()
結構就被消除了(想想為什麼,很簡單的道理)
然後我們 把 Val 重命名為 Object ,然後直接删除 ,這樣剩下的代碼中用到
Val
的地方也就全部變成了
Object
, 也就是我們所期望使用的那個類型啦。
https://blog.didispace.com/intellij-idea-refactoring-skills/#%E5%8F%A6%E4%B8%80%E7%A7%8D%E6%83%85%E5%86%B5 另一種情況
上面說的,是針對 “批量删除對于一個方法的調用” 的解決方案。
但我們有時不是想删除,而是增加。這怎麼辦嘞?
比如,我們現在有上面那段重構完了的代碼(which 沒有
getO()
)。
我們現在要把每一處
eval()
後面加上
toString()
(反正就是需要加一層方法調用)。
這個也很好解決,我們隻需要先把
eval()
随便改成(不是重命名,是直接改)另外一個名字(比如
rua
):
// code 0
interface Node { Object rua(); }
然後我們可以看到業務代碼全紅了:
然後我們再寫一個叫
eval
的方法,裡面傳回這個
rua
的調用結果再
toString()
(就是加上你要的那個方法調用):
// code 0
interface Node {
default Object eval() {
return rua().toString();
}
Object rua();
}
這時業務代碼已經不報錯了。
我們再對這個
eval()
進行
inline
,之後就是這個樣子的了:
然後再把
rua()
使用 IntelliJ 的重命名功能改成之前的
eval()
,就一切照舊啦。
https://blog.didispace.com/intellij-idea-refactoring-skills/#%E6%9C%AC%E6%96%87%E5%AE%8C 本文完
祝大家聖誕節快樂。
__________________________________________________
| _ |
| /|,/ _ _ _ / ` /_ _ . _ _/_ _ _ _ _|
|/ / /_' / / /_/ /_, / / / / _\ / / / / /_| _\ |
| _/ |
| ~~** ice1000 **~~ |
|__________________________________________________|
___
/` `'.
/ _..---;
| /__..._/ .--.-.
|.' e e | ___\_|/____
(_)'--.o.--| | | |
.-( `-' = `-|____| |____|
/ ( |____ ____|
| ( |_ | | __|
| '-.--';/'/__ | | ( `|
| '. \ )"";--`\ /
\ ; |--' `;.-'
|`-.__ ..-'--'`;..--'`
:*~*:._.:*~*:._.:*~*:._.:*~*:._.:*~*:._.:*~*:._.:*~*
這是一個來自 coding.net 的驚喜,我在推送代碼的時候看到的: