Move Method 遷移方法是最常用的重構之一。IntelliJ提供了這個自動化重構,快捷鍵 F6。在使用時會遇到如下問題
Client
package move_method_preserving_delegate;
public class Client {
void doSomethingWithFoo(Foo foo) {
foo.calculate();
}
}
Foo
package move_method_preserving_delegate;
public class Foo {
private Bar _bar;
int calculate() {
return _bar.getNumber() + 1;
}
}
Bar
package move_method_preserving_delegate;
public class Bar {
private int _number;
int getNumber() {
return _number;
}
}
Foo的代碼裡,calculate()的邏輯作用在Bar的屬性上,這個壞味使人想把calculate()的邏輯移到Bar上。如果在IntelliJ中用F6鍵移方法,結果如下
package move_method_preserving_delegate;
public class Client {
void doSomethingWithFoo(Foo foo) {
foo._bar.calculate();
}
}
package move_method_preserving_delegate;
public class Foo {
Bar _bar;
}
package move_method_preserving_delegate;
public class Bar {
private int _number;
int getNumber() {
return _number;
}
int calculate() {
return getNumber() + 1;
}
}
問題出現了,Foo的屬性bar可見度變成了公開,Foo也沒有保留原有的行為。顯然IntelliJ的自動化跳過了在原始對象上保留間接方法(Delegate)的這一步重構。解決的方法如下
在F6之前,先把要遷移的方法的邏輯全部代碼提取出來,因為不能和原方法同名,是以我加了個字尾_EX,表示是提取出來的
package move_method_preserving_delegate;
public class Foo {
private Bar _bar;
int calculate() {
return calculate_EX();
}
private int calculate_EX() {
return _bar.getNumber() + 1;
}
}
這樣就制造了一個中介方法,然後把它用F6移走
package move_method_preserving_delegate;
public class Foo {
private Bar _bar;
int calculate() {
return _bar.calculate_EX();
}
}
package move_method_preserving_delegate;
public class Bar {
private int _number;
int getNumber() {
return _number;
}
int calculate_EX() {
return getNumber() + 1;
}
}
最後重命名回calculate
package move_method_preserving_delegate;
public class Bar {
private int _number;
int getNumber() {
return _number;
}
int calculate() {
return getNumber() + 1;
}
}
package move_method_preserving_delegate;
public class Foo {
private Bar _bar;
int calculate() {
return _bar.calculate();
}
}
這樣做,Foo的Client代碼就沒有發生改變
package move_method_preserving_delegate;
public class Client {
void doSomethingWithFoo(Foo foo) {
foo.calculate();
}
}
之後是否要去掉中間人(Remove Middleman)是另一種重構要考慮的了。
***補充***
遷移方法同時保留中介,這步重構的反向操作是融回被遷走的方法
package move_method_preserving_delegate;
public class Bar {
private int _number;
int getNumber() {
return _number;
}
int calculate() {
return getNumber() + 1;
}
}
在Bar上選擇calculate(),然後融回(Inline,快捷鍵Ctrl + Alt + N),就回到使用遷移方法之前的狀态了。
package move_method_preserving_delegate;
public class Bar {
private int _number;
int getNumber() {
return _number;
}
}
package move_method_preserving_delegate;
public class Foo {
private Bar _bar;
int calculate() {
return _bar.getNumber() + 1;
}
}