【工利其器】必會工具之(四)Refactor篇——Android Studio在代碼重構中的妙用

       轉載請聲明,轉載自【http://www.javashuo.com/article/p-skndynew-r.html】,謝謝!html

       代碼重構幾乎是每一個程序員在軟件開發中必需要不斷去作的事情,以此來不斷提升代碼的質量。Android Stido(如下簡稱AS)以其強大的功能,成爲當下Android開發工程師最受歡迎的開發工具,也是Android官方推薦使用的工具。如此優秀的工具,天然少不了要在代碼重構這件事情上好好表現一把了。本文將經過代碼演示,功能截圖來詳細介紹AS爲代碼重構提供的各項功能。java

       在AS的主菜單欄中有一項「Refactor」下拉菜單,點擊該下拉菜單,會看到以下的界面,菜單中的每一項,都是爲代碼重構提供的一項自動實現功能。這麼多的功能項,可見AS在代碼重構功能上的強大,下面咱們對這些功能項一一進行介紹。另外,還能夠在編輯界面中點擊右鍵,在彈出的菜單中也能夠找到「Refactor」。android

 

一、Refactor This程序員

       做用:重構當前。操做此項,會顯示對當前光標選中處可行的重構方法。安全

       示例:選擇了類名「RefactorTest」,操做「Refactor This」後,顯示了可執行的重構方法列表,能夠經過選擇數字來執行對應的方法。app

       

 

二、Renameide

       做用:對光標選中項進行重命名。不只能夠對類中的成員變量進行重命名,還能對文件名,包名等進行重命名,Module中與之相關聯的全部地方都會一塊兒修改,而不用一一手動修改。函數

       快捷鍵:Shift + F6工具

       示例:在紅框中輸入修改後的名稱,並按Enter鍵便可。佈局

 

三、Rename File

       做用:修改當前編輯界面顯示的文件的文件名。就至關於鼠標選中該文件,並執行「Rename」方法。

       示例:在顯示的對話框中輸入新文件名。能夠在下方的選項框中選擇修改範圍,引用該文件的地方,註釋,字符串中均可以選擇一塊兒修改。

 

四、Change Signature

       做用:修改方法、類、構造函數的簽名,其實就是修改所選項的一些屬性。

       快捷鍵:Ctr l+ F6

       示例:以下展現了一個方法重構前,重構過程,以及重構後的情形(以修改一個方法簽名爲例)。

       重構前:

1 private void testChangeSignature(int first, int second) { 2 }

選中方法名後,執行該重構方法後,會彈出以下對話框,能夠對該方法各類屬性進行修改,添加/刪除參數,調整參數順序,新增/刪除異常等。

        重構後:

1 public void testChangeSignature(int second, int first, String third) throws NullPointerException { 2 }

 

五、Type Migration

       做用:類型遷移,即對變量數據類型,或者方法的返回類型進行修改。前面介紹了對文件名,包名,變量名等進行修改,這裏對類型進行修改。

       快捷鍵:Ctrl + Shift + F6

       重構前:

1 private int age = 10; 2 public RefactorTest(int age) { 3     this.age = age; 4 }

選中要修改的類型,執行該重構方法,會彈出對話框,根據須要編輯類型,選中做用範圍便可。指定範圍內,與該變量相關聯處都會被修改。

重構後(因爲從int修改到String,因此還須要手動修改變量值): 

1 private String age = "10"; 2 public RefactorTest(String age) { 3     this.age = age; 4 }

 

  六、Make Static

       做用:給內部類或者方法添加static關鍵字。示例比較簡單,就不作演示了。

       

  七、Convert To Instance Method

       做用: 轉換爲實例方法,即將靜態方法去掉static關鍵字。

 

  八、Move

       功能:移動文件到指定路徑

       快捷鍵:F6

 

九、Copy

       做用:在指定包中拷貝一份當前文件

       快捷鍵:F5

 

十、Safe Detele

       做用:安全刪除,可用於對方法/字段等進行快速刪除,會刪除掉與之相關聯的引用。

       快捷鍵:Alt + Delete

 

 

十一、Extract

   (1)Variable 

       做用:提取變量。這一點在碰到比較長的表達式時常常用到,將看起來很長很複雜的表達式提取出來做爲一個變量表示。

       快捷鍵:Ctrl + Alt + V

       重構前:咱們常會看到這樣的代碼

1 public void testExtractVariable() { 2      Log.i("demo", "age=" + getAaaaaaaaaaaaaaaaaaaaaaaaaaaAge() + ";name=" + getNnnnnnnnnnnnnnnnnnnnnnname()); 3  } 4  private int getAaaaaaaaaaaaaaaaaaaaaaaaaaaAge() { 5      return age; 6  } 7  private String getNnnnnnnnnnnnnnnnnnnnnnname() { 8      return name; 9  }

第二行的要打印的信息表達式太長了,但願單獨提取出來用一個變量表示。本示例中鼠標停留在第2行「getAaaaaaaaaaaaaaaaaaaaaaaaaaaAge」處,執行該重構方法,會彈出以下紅框部分對話框,顯示的是選中表達式相關的可提取部分,根據須要選擇要提取的部分便可。

重構後: 

 1 public void testExtractVariable() {  2     String msg = "age=" + getAaaaaaaaaaaaaaaaaaaaaaaaaaaAge() + ";name=" + getNnnnnnnnnnnnnnnnnnnnnnname();  3     Log.i("demo", msg);  4 }  5 private int getAaaaaaaaaaaaaaaaaaaaaaaaaaaAge() {  6     return age;  7 }  8 private String getNnnnnnnnnnnnnnnnnnnnnnname() {  9     return name; 10 }

    (2)Constant

       做用:提取常量,將表達式中的值提取爲常量。

       快捷鍵:Ctrl + Alt +C

       重構前:

1 public void testExtractConstant() { 2   String filename = "sdcard"; 3 }

重構後:

1 public static final String SDCARD = "sdcard"; 2 public void testExtractConstant() { 3   String filename = SDCARD; 4 }

    (3)Filed

       做用:提取字段,將局部變量提取爲全局變量。

       快捷鍵:Ctrl + Alt +F

       重構前:

1 public void testExtractField() { 2    String name ="zhangsan"; 3 }

        重構後:

1 private final String string = "zhangsan"; 2 public void testExtractField() { 3 }

    (4)Parameter

       做用:將局部變量提取爲方法的參數。

       快捷鍵:Ctrl + Alt +P

       重構前:

1 public void testExtractParameter() { 2  printName(); 3 } 4 private void printName(){ 5     String name = "zhangsan"; 6     Log.i("demo","My name is:"+name); 7 }

      重構後:

1 public void testExtractParameter() { 2     printName("zhangsan"); 3 } 4 private void printName(String name){ 5     Log.i("demo","My name is:"+ name); 6 }

    (5)Functional Parameter ( 函數式參數 ) Ctrl + Alt + Shift + P

    (6)Parameter Object

       做用:將參數提取爲一個對象。該功能主要是針對參數比較多的時候,將這些參數提取出來做爲一個Bean實例傳入。

       重構前:

1 private void testExtractParamObject() { 2     String info = getInfo("zhangshan", 20, 180f); 3 } 4 private String getInfo(String name, int age, float height) { 5     return "name=" + name + ";age=" + age + ";height=" + height; 6 }

       重構後:

 1 private void testExtractParamObject() {  2     String info = getInfo(new Person("zhangshan", 20, 180f));  3 }  4 private String getInfo(Person person) {  5     return "name=" + person.getName() + ";age=" + person.getAge() + ";height=" + person.getHeight();  6 }  7 private static class Person {  8     private final String name;  9     private final int age; 10     private final float height; 11     private Person(String name, int age, float height) { 12         this.name = name; 13         this.age = age; 14         this.height = height; 15  } 16     public String getName() { 17         return name; 18  } 19     public int getAge() { 20         return age; 21  } 22     public float getHeight() { 23         return height; 24  } 25 }

    (7)Mehtod

       做用:提取爲方法

       快捷鍵:Ctrl + Alt +M

       重構前:

1 public void testExtractMethod() { 2     List<String> nameList = new ArrayList<>(); 3     nameList.add("zhangshan"); 4     nameList.add("lisi"); 5     nameList.add("wangwu"); 6     int size = nameList.size(); 7 }

鼠標光標選中第2~5行後執行該重構方法

        重構後:

 1 public void testExtractMethod() {  2     List<String> nameList = getNameList();  3     int size = nameList.size();  4 }  5 @NonNull  6 private List<String> getNameList() {  7     List<String> nameList = new ArrayList<>();  8     nameList.add("zhangshan");  9     nameList.add("lisi"); 10     nameList.add("wangwu"); 11     return nameList; 12 }

    (8)Type Parameter

    (9)Method Object

       做用:將該選中的內容提取爲一個方法,並提取到一個獨立的類中。和「Method」很相似,不一樣的是提取的方法最後放在哪裏。

       重構前:

1 public void testExtractMethod() { 2     List<String> nameList = new ArrayList<>(); 3     nameList.add("zhangshan"); 4     nameList.add("lisi"); 5     nameList.add("wangwu"); 6     int size = nameList.size(); 7 }

        重構後:

 1 public void testExtractMethod() {  2     List<String> nameList = Utils.invoke();  3     int size = nameList.size();  4 }  5 private static class Utils {  6     private static List<String> invoke() {  7         List<String> nameList = new ArrayList<>();  8         nameList.add("zhangshan");  9         nameList.add("lisi"); 10         nameList.add("wangwu"); 11         return nameList; 12  } 13 }

    (10)Delegate

       做用:提取爲一個代理類。

       重構前:

1 public class RefactorTest{ 2 
3     public void testExtractInterface() { 4         System.out.print("testExtractInterface"); 5  } 6 }

       重構後:

 1 public class RefactorTestDelegate {  2     public RefactorTestDelegate() {  3  }  4 
 5     public void testExtractInterface() {  6         System.out.print("testExtractInterface");  7  }  8 }  9 
10 public class RefactorTest{ 11 
12     private final RefactorTestDelegate refactorTestDelegate = new RefactorTestDelegate(); 13 
14     public void testExtractInterface() { 15  refactorTestDelegate.testExtractInterface(); 16  } 17 }

    (11)Interrface

       做用:提取爲接口。

       重構前:

1 public class RefactorTest { 2 
3     public void testExtractInterface() { 4         System.out.print("testExtractInterface"); 5  } 6 }

public修飾的方法才能夠被提取到接口中。

        重構後: 

 1 interface IRefactorTest {  2     void testExtractInterface();  3 }  4 
 5 public class RefactorTest implements IRefactorTest {  6 
 7  @Override  8     public void testExtractInterface() {  9         System.out.print("testExtractInterface"); 10  } 11 }

    (12)Superclass

       做用:將指定內容提取到父類中。

       重構前:

1 private void testExtractSupperclass() { 2  testSuper(); 3 } 4 
5 public void testSuper() { 6      System.out.print("testSuper"); 7 }

       重構後:

 1 //=======RefactorTest extends RefactorTestBase=======
 2 private void testExtractSupperclass() {  3  testSuper();  4 }  5 
 6 class RefactorTestBase {  7     public void testSuper() {  8         System.out.print("testSuper");  9  } 10 }

    (13) Style

       做用:將屬性提取爲Style。該項只有當鼠標停留在佈局文件中時纔會出現。

       重構前:

1 <Button 2     android:id="@+id/btn_handler_demo"
3  android:layout_width="wrap_content"
4  android:layout_height="wrap_content"
5  android:text="handler" />

       

       重構後:

1 <Button 2     android:id="@+id/btn_handler_demo"
3  android:text="handler"
4  style="@style/testStyle" />

 styles.xml

1 <?xml version="1.0" encoding="utf-8"?>
2 <resources>
3     <style name="testStyle">
4         <item name="android:layout_width">wrap_content</item>
5         <item name="android:layout_height">wrap_content</item>
6     </style>
7 </resources>

    (14)Layout

       做用:提取爲佈局文件。這一項也是須要在鼠標停留在佈局文件中時纔會出現。

 1 <LinearLayout  2     android:layout_width="match_parent"
 3  android:layout_height="wrap_content"
 4  android:orientation="horizontal">
 5     <Button  6         android:id="@+id/btn_handler_demo"
 7  android:layout_width="wrap_content"
 8  android:layout_height="wrap_content"
 9  android:text="handler" />
10     <Button 11         android:id="@+id/btn_broadcast_demo"
12  android:layout_width="wrap_content"
13  android:layout_height="wrap_content"
14  android:text="Broadcast" />
15     <Button 16         android:id="@+id/btn_bright_demo"
17  android:layout_width="wrap_content"
18  android:layout_height="wrap_content"
19  android:text="Bright" />
20     <Button 21         android:id="@+id/btn_service_demo"
22  android:layout_width="wrap_content"
23  android:layout_height="wrap_content"
24  android:text="Service" />
25 </LinearLayout>

       重構後:

<include layout="@layout/testlayout" />

testlayout.xml

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3  xmlns:tools="http://schemas.android.com/tools"
 4  android:layout_width="match_parent"
 5  android:layout_height="wrap_content"
 6  android:orientation="horizontal"
 7  tools:showIn="@layout/activity_main">
 8 
 9     <Button 10         android:id="@+id/btn_preference_demo"
11  android:layout_width="wrap_content"
12  android:layout_height="wrap_content"
13  android:text="Preference" />
14 
15     <Button 16         android:id="@+id/btn_file_demo"
17  android:layout_width="wrap_content"
18  android:layout_height="wrap_content"
19  android:text="File" />
20 
21     <Button 22         android:id="@+id/btn_anim_demo"
23  android:layout_width="wrap_content"
24  android:layout_height="wrap_content"
25  android:text="Anim" />
26 
27     <Button 28         android:id="@+id/btn_customview_demo"
29  android:layout_width="wrap_content"
30  android:layout_height="wrap_content"
31  android:text="CustomView" />
32 </LinearLayout>

 

十二、Inline

       做用:轉換爲內聯、方法鍊形式的調用。

       快捷鍵:Ctrl + Alt +N

       重構前:

1 private void testInline() { 2     int a = 100; 3     int b = 200; 4  System.out.print(add(a, b)); 5 } 6 private int add(int a, int b) { 7     System.out.print("a=" + a + ";b=" + b); 8     return a*2 + b*3; 9 }

       重構後: 

1 private void testInline() { 2     int a = 100; 3     int b = 200; 4     System.out.print("a=" + a + ";b=" + b); 5     System.out.print(a * 2 + b * 3); 6 }

原先須要調用一個方法,重構後直接把該方法中的代碼給複製過來了。由於上面選中的是內聯全部的,而且刪除該方法,因此add方法也就被刪除了。

 

1三、Find and Replace Code Duplicates

 

1四、Invert Boolean

       做用:轉換Boolean值,將當前false/true的值進行轉化爲相反的值。

       重構前:

1 private boolean isEmpty(String str) { 2     if (str != null && str.length() == 0) { 3         return false; 4  } 5     return true; 6 }

       重構後:

1 private boolean isNotEmpty(String str) { 2     if (str != null && str.length() == 0) { 3         return true; 4  } 5     return false; 6 }

 

1五、Pull Members Up

       做用:將子類的成員上移到父類中。

       重構前:

 1 public class RefactorBase {  2 
 3 }  4 
 5 public class RafactorSub extends RefactorBase {  6     int age = 10;  7 
 8     public void printSub() {  9  System.out.print(age); 10  } 11 }

       重構後:

 1 public class RefactorBase {  2     int age = 10;  3     public void printSub() {  4  System.out.print(age);  5  }  6 }  7 
 8 public class RafactorSub extends RefactorBase {  9 
10 }

 

1六、Push Members Down

       做用:將父類中的成員下移到子類中,正好是「Pull Members Up」的反向操做。

       重構前:

 1 public class RefactorBase {  2     int age = 10;  3     public void printSub() {  4  System.out.print(age);  5  }  6 }  7  
 8 public class RafactorSub extends RefactorBase {  9  
10 }

       重構後:

1 public class RefactorBase { 2 
3 } 4 public class RafactorSub extends RefactorBase { 5     int age = 10; 6     public void printSub() { 7  System.out.print(age); 8  } 9 }

 

1七、Use Interface Where Possible

 

1八、Replace Inheritance with Delegation

       做用:使用代理替代繼承。在java中,提倡使用組合,而不是繼承。

       重構前:

 1 public abstract class AbsClass {  2     public abstract void print();  3 }  4 
 5 public class ClassWrapper extends AbsClass {  6  @Override  7     public void print() {  8         System.out.print("print");  9  } 10 } 11 
12 private void testReplaceInheritanceWithDelegation() { 13     new ClassWrapper().print(); 14 }

        重構後:

 1 public abstract class AbsClass {  2     public abstract void print();  3 }  4 
 5 public class ClassWrapper {  6     private final ClassImpl absClass = new ClassImpl();  7 
 8     public void print() {  9  absClass.print(); 10  } 11 
12     private class ClassImpl extends AbsClass { 13  @Override 14         public void print() { 15             System.out.print("print"); 16  } 17  } 18 } 19 
20 public class RefactorTest { 21     private void testReplaceInheritanceWithDelegation() { 22         new ClassWrapper().print(); 23  } 24 }

 這一部分有點像Android中Context,ContextWrapper,ContextImpl類之間的關係。

 

1九、Remove Middleman

       做用:移除中間人,其實就是移除中間過程。

       重構前:

 1 public class RefactorTest {  2 
 3     private void testRemoveMiddleMan() {  4         BookManager bookManager = new BookManager();  5         bookManager.addBook("java");  6  }  7 
 8     public static class BookManager {  9         private List<String> mBookList = new ArrayList<>(); 10 
11         private void addBook(String bookName) { 12  mBookList.add(bookName); 13  } 14  } 15 }

       重構後:

 1 public class RefactorTest {  2 
 3     private void testRemoveMiddleMan() {  4         BookManager bookManager = new BookManager();  5         bookManager.getmBookList().add("java");  6  }  7 
 8     public static class BookManager {  9         private List<String> mBookList = new ArrayList<>(); 10 
11         public List<String> getmBookList() { 12             return mBookList; 13  } 14  } 15 }

對比重構前和重構後會發現,添加book這個動做,從由BookManager的addBook方法來執行,變成了直接有mBookList來執行了。這個addBook就是這個MiddleMan,顯得多餘,能夠優化掉。實際上優化後就變成一個inline方式了,能夠對比前面講到的「Inline」。

 

20、Wrap Method Return Value

       做用:封裝返回值

 1 public class RefactorTest {  2 
 3     private void testWrapReturnValue() {  4         String name = getName();  5  }  6 
 7     private String getName() {  8         return "zhangsan";  9  } 10 }

       重構後:

 1 public class RefactorTest {  2 
 3     private void testWrapReturnValue() {  4         String name = getName().getValue();  5  }  6 
 7     private Person getName() {  8         return new Person("zhangsan");  9  } 10 
11     public class Person { 12         private final String value; 13 
14         public Person(String value) { 15             this.value = value; 16  } 17 
18         public String getValue() { 19             return value; 20  } 21  } 22 }

 

2一、Convert Anonymous to Inner

       做用:將匿名內部類轉爲內部類。

       重構前:

1 private void testConvertAnonymousToInner(){ 2     view.setOnClickListener(new View.OnClickListener() { 3  @Override 4         public void onClick(View v) { 5  } 6  }); 7 }

        重構後:

 1 public class RefactorTest{  2 
 3  View view;  4     private void testConvertAnonymousToInner(){  5         view.setOnClickListener(new MyOnClickListener());  6  }  7 
 8     private static class MyOnClickListener implements View.OnClickListener {  9  @Override 10         public void onClick(View v) { 11 
12  } 13  } 14 }

 

2二、Encapsulate Fields

       做用:封裝字段,用於生成Getter/Setter

       重構前:

1 public String name = "zhangsan"; 2 private void testEncapsulateFields() { 3  System.out.println(name); 4 }

 經過該對話框,能夠選擇要封裝的字段,設置修飾符等。默認選擇時,name字段的修飾符從public變成了private,這也就避免了外部類經過實例直接訪問它。

       重構後:

 1 private String name = "zhangsan";  2 private void testEncapsulateFields() {  3  System.out.println(getName());  4 }  5 public String getName() {  6     return name;  7 }  8 public void setName(String name) {  9     this.name = name; 10 }

 

2三、Replace Temp With Query

 

2四、Replace Constructor with Factory Method

       做用:將構造方法替換爲工廠方法

       重構前:

 1 public class MyClass {  2 
 3     private String title;  4     private String message;  5     private String sure;  6     private String cancel;  7 
 8     public MyClass(String title, String message, String sure, String cancel) {  9         this.title = title; 10         this.message = message; 11         this.sure = sure; 12         this.cancel = cancel; 13  } 14 } 15 
16 public class RefactorTest { 17     private void testReplaceConstructorWithFactory(Context context) { 18         MyClass myClass = new MyClass("title", "message", "sure", "cancle"); 19  } 20 }

       重構後:

 1 public class MyClass {  2 
 3     private String title;  4     private String message;  5     private String sure;  6     private String cancel;  7 
 8     private MyClass(String title, String message, String sure, String cancel) {  9         this.title = title; 10         this.message = message; 11         this.sure = sure; 12         this.cancel = cancel; 13  } 14 
15     public static MyClass createMyClass(String title, String message, String sure, String cancel) { 16         return new MyClass(title, message, sure, cancel); 17  } 18 } 19 
20 public class RefactorTest { 21     private void testReplaceConstructorWithFactory(Context context) { 22         MyClass myClass = MyClass.createMyClass("title", "message", "sure", "cancle"); 23  } 24 }

原先public修飾的構造函數,已經變成private了,MyClass類只能經過工廠方法來獲取實例,而沒法再直接new了。

 

2五、Replace Constructor with Builder

       做用:將構造方法替換爲Builder方式

       重構前:

 1 public class RefactorTest{  2     private void testReplaceConstructorWithBuilder(Context context){  3         MyDialog dialog =  new MyDialog(context,"title","message","sure","cancle");  4  }  5 }  6 
 7 public class MyDialog extends Dialog {  8     private String title;  9     private String message; 10     private String sure; 11     private String cancel; 12     public MyDialog(@NonNull Context context) { 13         super(context); 14  } 15     public MyDialog(Context context, String title, String message, String sure, String cancel) { 16         super(context); 17         this.title = title; 18         this.message = message; 19         this.sure = sure; 20         this.cancel = cancel; 21  } 22 }

 

重構後:

 1 public class RefactorTest {  2     private void testReplaceConstructorWithBuilder(Context context) {  3         MyDialog dialog = new MyDialogBuilder()  4  .setContext(context)  5                 .setTitle("title")  6                 .setMessage("message")  7                 .setSure("sure")  8                 .setCancel("cancle")  9  .createMyDialog(); 10  } 11 } 12 
13 public class MyDialogBuilder { 14     private Context context; 15     private String title; 16     private String message; 17     private String sure; 18     private String cancel; 19 
20     public MyDialogBuilder setContext(Context context) { 21         this.context = context; 22         return this; 23  } 24 
25     public MyDialogBuilder setTitle(String title) { 26         this.title = title; 27         return this; 28  } 29 
30     public MyDialogBuilder setMessage(String message) { 31         this.message = message; 32         return this; 33  } 34 
35     public MyDialogBuilder setSure(String sure) { 36         this.sure = sure; 37         return this; 38  } 39 
40     public MyDialogBuilder setCancel(String cancel) { 41         this.cancel = cancel; 42         return this; 43  } 44 
45     public MyDialog createMyDialog() { 46         return new MyDialog(context); 47  } 48 }

看到這裏,咱們應該可以聯想到AlertDialog類中的Builder了。將構造函數的形式,轉變爲了建造者模式的形式,這樣不會拘泥於構造函數的參數個數,參數類型的限制,從而靈活設置屬性。 

 

2六、Generify

       做用:泛型重構,自動添加泛型的參數。

       重構前:

1 private void testGenerify() { 2     List list = new ArrayList(); 3     list.add("one"); 4     list.add("two"); 5     list.add("three"); 6 }

       重構後:

1 private void testGenerify() { 2     List<String> list = new ArrayList<String>(); 3     list.add("one"); 4     list.add("two"); 5     list.add("three"); 6 }

2七、Migrate

2八、Internationalize(國際化)

 

2九、Remove Unused Resources

       做用:一直不用的資源

       示例:下圖中1.jpg是一個沒有被應用的文件。

 

 

在執行該重構方法後,1.jpg就被刪除了。

 

 

參考:https://www.jianshu.com/p/f8cb51bc8e19

相關文章
相關標籤/搜索