1. 程式人生 > >第四章:重構代碼[學習Android Studio漢化教程]

第四章:重構代碼[學習Android Studio漢化教程]

出現 introduce 編輯 rri 分享 成員 dialog fig ice

第四章

Refactoring Code

The solutions you develop in Android Studio will not always follow a straight path from design to finish. To be an effective Android programmer, you need to be flexible and refactor your code as you develop, debug, and test. In the preceding chapter, you learned how Android Studio can generate code; in this chapter, you’re going to see how Android Studio can refactor your code. The greatest risk with refactoring code is that you may introduce unintended errors. Android Studio mitigates these risks by analyzing the consequences of certain risky refactoring operations, and then activates the Find tool window, in which you may preview your changes—flagged with any errors or conflicts—before committing them.
<翻譯>

第四章

重構代碼

在Android Studio中開發,解決方案不會總是一蹴而成的。作為一個有效率的編程者,在你的開發,調試和測試中需要一些彈性以及代碼重構。隨著在這章中的行進,你將明白Android Studio如何產生代碼;在這章裏你將看到Android Studio如何重構你的代碼。重構代碼最大的風險是可能引入不期望的錯誤。通過分析某些風險重構操作的結果,Android Studio減低了這些風險,然後激活Find tool窗口,在發行前,你可以預覽你的更改-那裏標誌著任何錯誤或沖突。

Many of the refactoring operations presented in this chapter can also be performed without Android Studio’s refactoring tools. However, you should avoid refactoring by brute force (for example, by resorting to a global find-and-replace option) because Android Studio cannot always save you from introducing errors in those circumstances. In contrast, if Android Studio detects that you’re attempting a refactoring operation, it will try to prevent
you from making any stupid mistakes. For example, dragging a Java source file from one package to another in the Project tool window will force a Refactor ? Move operation, which analyzes the consequences of your move operation, allows you to preview the changes, and then gracefully changes any import statements for that class throughout your entire project to the new fully qualified package name.
<翻譯>
在這章裏描述的許多重構操作也可不用Android Studio的重構工具來執行。無論怎樣,你必須避免強行重構(例如:通過一個全文的查找/替換操作來重組代碼),因為在這些情形下Android Studio不能從引入的錯誤中一直保護你。相反,如果Android Studio發現你企圖一個重構操作,它將盡力避免你犯任何愚蠢錯誤。例如,在Project tool窗口中拖動一個JAVA源文件從一個包到另一個包,這將強制產Refactor ? Move操作,由此會分析你的移動操作結果,允許你預覽那些改變,然後適當地改變類中所有的import語句以適應合格的新全包名。

Most refactoring operations are confined to one method or one class, and thus will not likely introduce errors into your project. Risky refactoring operations are those that involve two or more assets. If a refactoring operation introduces compilation errors, the Inspections Manager will flag the affected assets with red tags in the Editor. At that point, you can either attempt to fix them, or simply undo the entire refactoring operation by pressing Ctrl+Z | Cmd+Z. If the refactor operation succeeded with no compilation errors, but nevertheless involved a lot of assets, you should still run your tests to verify that you have not introduced any runtime errors. Chapter 11 covers testing.
<翻譯>
絕大多數的重構操作被限制於一個方法或一個類裏面,因而將不太會引入錯誤到你的項目中。危險的重構操作是那些涉及到兩個或以上的資源文件。如果重構操作引入編譯錯誤,檢查管理器將在編輯器裏用紅標簽標誌那些被影響的資源文件。基於這點,你或者可以企圖去修正它們,或者用Ctrl+Z|Cmd+Z簡單地取消這個重構操作了。如果重構操作以沒有編譯錯誤完成,然而涉及到太多資源文件,那你還是必須要測試及校驗你是否引入了任何實時錯誤。第11章涵蓋了測試。

Tip: You should commit any significant refactoring changes as a single Git commit so that you can easily revert that commit later. Chapter 7 covers Git.
<翻譯>
提示:你必須提交任何重要的重構更改,作為單一的Git提交,因此之後你可以輕松地回復那個提交。第7章涵蓋了Git。

This chapter focuses on the refactoring operations with the greatest utility. Before we begin addressing individual refactoring operations, we’d like to point out that Android Studio has an extremely convenient refactoring operation called Refactor ? Refactor This. Choosing this option displays a context menu, shown in Figure 4-1, that aggregates the most useful refactoring operations. The keyboard shortcut for this operation is Ctrl+Alt+Shift+T | Ctrl+T, and on a PC you can remember it by its conveniently mnemonic acronym: CAST.
<翻譯>
這章聚焦於用最好的工具來執行重構操作。在我們探訪獨立的重構操作之前,我們樂於指出Android Studio有一個極其便利的重構工具叫Refactor ?Refactor This.總在上下文菜單中選擇這個,圖4-1所示,集成了絕大多數有用的重構操作。快捷鍵是Ctrl+Alt+Shift+T | Ctrl+T,在PC上你可以方便地記首字母CAST。

技術分享圖片


圖4-1:重構器Refactor This菜單,包括了大部分的有用重構操作。

Before you begin working on the examples in this chapter, modify the Sandbox.java file from Chapter 3 so that it extends nothing and contains neither methods nor members, like the following snippet:
public class Sandbox {
}
<翻譯>
在你開始本章的例子之前,修改第3章的Sandbox.java文件,它沒擴充和包含任何方法或成員變量,象下面的小片段:
public class Sandbox {
}

Rename

Select Sandbox from the Project tool window and then navigate to Refactor ? Rename or press Shift+F6. The resulting dialog box allows you to rename your class and rename any additional occurrences of that name in comments, test cases, and inherited classes. Rename Sandbox to Playpen and click the Refactor button, shown in Figure 4-2. You should see the results of the Renaming operation in your project. Now undo the Renaming
operation by pressing Ctrl+Z | Cmd+Z.
<翻譯>

重命名

在Project tool窗口中選擇Sandbox並導航到Refactor? Rename或按Shift+F6.引出一個對話框以允許你重命名你的類,另外也可以重命名出現在註釋中,測試實例,以及繼承類中的那些名字。重命名Sandbox為Playpen並點擊Refactor按鈕,如圖4-2所示。你將看到在你項目中重命名的操作。現在請用Ctrl+Z | Cmd+Z取消這個操作。

技術分享圖片


圖4-2:重命名Sandox為Playpen

Change Signature

The Change Signature operation enables you to change the following properties of a method:visibility, name, return type, parameters, and exceptions thrown. Create a method inSandbox.java, as shown in this code snippet:
public String greetings(String message){
return "Hello " + message;
}

<翻譯>

修改簽名

更改簽名的操作允許你改變方法的下列屬性:可視性,名稱,返回類型,參數,以及例外拋出。在Sandbox.java裏創建一個方法,如下面的代碼片斷:
public String greetings(String message){
return "Hello " + message;
}

Place your cursor anywhere on the word greetings (highlighted in bold) and press Ctrl+F6 | Cmd+F6, or navigate to Refactor ? Change Signature. The resulting dialog box enables you to modify the signature of the method, as shown in Figure 4-3.
<翻譯>
將光標移到單詞greetings上面(高亮的粗體字)並按Ctrl+F6 |Cmd+F6,或導航到Refactor ? Change Signature。結果對話框會允許你修改方法的簽名,如圖4-3所示。

技術分享圖片


圖4-3:修改簽名對話框

In the Parameters tab, click the String message item. Change the name of the String parameter from message to greet, as shown in Figure 4-3. The green-plus and red-minus icons allow you to add parameters to or subtract parameters from your method, respectively; and you may edit their types and names in the list. In addition to modifying the current method, you may decide to select the Delegate via Overloading Method radio button. Selecting this radio button will leave your original method unaffected, but generate another method with the new signature you define. A set of methods may be considered overloaded in Java if they have
the same name, but the parameter order and/or parameter types are different. However, the change we made does not qualify this method for overloading. You may preview your changes before committing them by clicking the Preview button if you so choose. To complete the operation and dismiss the dialog box, click the Refactor button.
<翻譯>
在參數表裏,點擊字符串類型參數message這項,將它的名稱從message改為greet,如圖4-3所示。圖標綠色的+和紅色的-允許你分別增加或減少方法的參數。並且,你也可以編輯參數表裏面它們的類型和名稱。另外,修改當前方法時,你可能決定選擇委托重載方法的單選按鈕。選擇這個按鈕將保留你的原始方法不受影響,但會生成另一個你新定義簽名的方法。在JAVA裏如果你可能考慮一系列有相同的名稱重載方法,但參數的順序和/或參數的類型不同。無論如何,你做的更改並沒限制方法的重載。如果你希望的話通過點擊預覽按鈕,可以在提交它們之前預覽。按Refactor按鈕完成並離開。

Type Migration

As the name suggests, type migration allows you to migrate from one Java type to another. Let’s assume that you create a Person class. Further along in your development, you discover that Person is too generic, so you create a Manager class that extends Person. If you want to migrate all instances of Person to Manager, you can do this easily with type migration.
<翻譯>

類型移植

如標題所述,類型移植允許你從一個JAVA類型移植到另一個。讓我們假設你創建了一個Person類。隨著你的開發進行,你發現Person太一般了,因而你又創建了一個Manager類擴展於Person。如果你想移植所有的Person實例到Manager,你可以用類型移植輕松辦到。

Place your cursor on the String declaration (highlighted in bold in the following code snippet) of the greetings method and press Ctrl+Shift+F6 | Cmd+Shift+F6 or choose Refactor ? Type Migration. The resulting dialog box resembles that seen in Figure 4-4.
public String greetings(String greet){
return "Hello " + greet;
}
<翻譯>
將光標放到greetings方法的String聲明上(在下面代碼片段中的高亮粗體字)並且按Ctrl+Shift+F6 | Cmd+Shift+F6或選擇Refactor ? Type Migration。結果對話框如圖4-4所示。
public String greetings(String greet){
return "Hello " + greet;
}

技術分享圖片


圖4-4:類型移植,從String到date

Change java.lang.String to java.util.Date, as shown in Figure 4-4. Select Open Files from the Choose Scope drop-down list. As with most refactor operations, you can preview your changes by clicking the Preview button. Click the Refactor button.
<翻譯>
更改java.lang.String到java.util.Date,如圖4-4所示。從選擇範圍框的下拉菜單裏選擇打開文件。如同大多數重構操作,通過點擊預覽按鈕,你可預覽你的更改。這裏我們按Refactor按鈕。

Move

You can move a source file in one of three ways:
? By dragging the source file from one package to another in the Project tool window
? By selecting that source file and navigating to Refactor ? Move from the main menu
? By selecting the file in the Project tool window and pressing F6
Right-click (Ctrl-click on Mac) the com.apress.gerber.helloworld package and choose New ? Package. Name the package refactor. From the Project tool window, drag and drop the Sandbox class to the refactor package and press OK when prompted by the dialog shown in Figure 4-5. Any drag-and-drop operation you perform in the Project tool window automatically forces a Refactor ? Move operation, which allows you to safely move your class from one package to another.
<翻譯>

移動

你可以通以下三種方法中的一個方法來移動源代碼文件。
?在Project tool窗口拖動源文件從一個包到另一個包中;
?選擇源文件從主菜單導航到Refactor ? Move;
?在Project tool窗口選擇源文件並按下F6。
右鍵點擊(在Mac電腦上Ctrl-click)com.apress.gerber.helloworld包並選擇New ? Package。給這個重構目標包命名。從Project tool窗口,把sandbox.java拖放到重構目標包裏,當出現圖4-5對話框時按OK。在Project tool窗口中執行的任何拖放操作將自動產生一個重構移動操作,這個會讓你安全地把一個類從一個包移動到別一個包裏。

技術分享圖片


圖4-5:由於拖放操作導致的重構移動對話框

In addition to moving classes, you may also move members. In your Sandbox class, define a new member like the following:
public static final String HELLO = "Hello Android Studio";
<翻譯>
除了移動類之外,你也可以移動成員變量。在你的Sandbox.class中,定義一個新成員變量如下:
public static final String HELLO = "Hello Android Studio";

Place your cursor on this line of code and press F6. The resulting dialog box allows you to move members from one class to another, as shown in Figure 4-6. Click the Cancel button to cancel this operation.
<翻譯>
移動光標到這行代碼上並按下F6。導致一個對話框允許你移動成員變量從一個類到另一個。如圖4-6所示。請點擊取消按鈕來取消這次操作。

技術分享圖片


圖4-6:移動成員變量的對話框

Copy

Copy, which is similar to Move, is accessed by pressing the keyboard shortcut F5 or by
choosing Refactor ? Copy from the main menu. In the Project tool window, select the Sandbox class in the refactor package and press F5. Select the com.apress.gerber.helloworld package from the Destination Package drop-down menu and click OK, as shown in Figure 4-7. Copying Java source files indiscriminately as we did here is not a good idea because the resolution is ambiguous and thus rife for potential errors.
<翻譯>

復制

復制,有點象移動,按快捷鍵F5或選擇主菜單裏的Refactor ? Copy來訪問。在Project tool窗口,選擇之前重構的包中的Sandbox.java並按下F5鍵。在目標包的拖放菜單中選擇com.apress.gerber.helloworld包並點擊OK,如圖4-7所示。象我們這裏無差別地復制JAVA源文件不是一個好主意,因為結果不明確且普通存在著錯誤。

技術分享圖片


圖4-7:復制類的對話框

Safe Delete

Let’s delete the copied class we created. You can always delete files and resources in Android Studio by selecting them in the Project tool window and pressing the Delete key. Click the Sandbox file in the refactor package and press Delete. The resulting dialog box allows you to use the Safe Delete option by selecting the Safe Delete check box. The advantage of using Safe Delete is that we can search any dependencies on the asset that might be broken before performing the delete, as shown in Figure 4-8. If any dependencies of this asset are found in your project, you will be given the option to view them, or force the delete operation anyway by clicking Delete Anyway.
<翻譯>

安全刪除

讓我們來刪除剛才復制的類。在Android Studio的Project tool窗口裏用Delete按鍵,你總可以刪除文件和資源。在剛才重構包中點擊Sandbox.java文件並按下Delete鍵。結果對話框允許你使用安全刪檢查選項來刪除。安全刪除的先進之處在於執行刪除前我們可查詢任何因依賴於這個資產而可能導致的破壞,如圖4-8所示。如果在這個項目中發任何東西依賴於這個資產,將給出一個可選項瀏覽它們,或點擊無論如何都刪除可選項來強制刪除。

技術分享圖片


圖4-8:安全刪除對話框

Extract

Extract isn’t just one operation but several. This section covers some of the more important extract operations: Extract Variable, Extract Constant, Extract Field, Extract Parameter, and Extract Method. In the Sandbox class, let’s start with a clean slate by removing all the members and methods:
public class Sandbox {
}
<翻譯>

析出

析出不是一個操作而是幾個。這節涵括了一些重要的析出操作:析出變量,析出常量,析出域,析出參數,和析出方法。在Sandbox.class裏,讓我們先移走所有的成員變量和方法從白紙開始:
public class Sandbox {
}

Extract Variable

In your Sandbox.java class, define a method, as shown here:
private String saySomething(){
return "Something";
}
<翻譯>

析出變量

在你的Sandbox.java類裏,定義一個方法如下示:
private String saySomething(){
return "Something";
}

Place your cursor anywhere on the hard-coded Something value (highlighted in bold) and
choose Refactor ? Extract ? Variable, or press Ctrl+Alt+V | Cmd+Alt+V and then press Enter without selecting the Declare final checkbox. Android Studio extracts a local variable and names it according to the hard-coded String. You should end up with something like this:
private String saySomething(){
String something = "Something";
return something;
}
<翻譯>
把光標放到硬編碼Something的值(粗體字)上並選擇Refactor ? Extract ? Variable,或者按Ctrl+Alt+V | Cmd+Alt+V接著按回車,不要選擇聲明final的復選框。Android Studio依據硬編碼字符串析出一個本地變量並命名它。你將以如下代碼告終:
private String saySomething(){
String something = "Something";
return something;
}

Extract Constant

As you develop apps in Android, you will find yourself using a lot of Strings as keys—for
example, in Maps and Bundles. Therefore, extracting constants will save you a lot of time.
<翻譯>

析出常量

當你開發Android的APP時,會發現你會用很多的字符串作為鍵-例如,在Map和Bundle裏。因此,析出常量將會節省你大量的時間。

Define a method like the one seen in the following code snippet. Place your cursor anywhere on the name_key string and press Ctrl+Alt+C | Cmd+Alt+C. The resulting dialog box should look like Figure 4-9. Here, Android Studio provides a few suggestions for names. By convention, constants in Java are all caps. Select NAME_KEY and press Enter.
Note You will need to import android.os.Bundle in order to create the proceding method without compile-time errors.
private void addName(String name, Bundle bundle ){
bundle.putString("name_key", name);
}

<翻譯>
定義一個方法象如下的代碼片段。把光標放到name_key字符串上並按Ctrl+Alt+C | Cmd+Alt+C。結果對話框將如圖4-9所示。這裏,Android Studio提供一些建議的名稱。按慣例,常量在JAVA裏都應該是大寫的。選擇NAME_KEY並按回車。
註意:為了創建和處理這個方法而不發生編譯錯誤,你必須導入android.os. Bundle
private void addName(String name, Bundle bundle ){
bundle.putString("name_key", name);
}

You should end up with a constant called NAME_KEY, which should be defined like this:
public static final String NAME_KEY = "name_key";
<翻譯>
結束時你將看一個常量名稱是NAME_KEY,象以下定義的:
public static final String NAME_KEY = "name_key";

技術分享圖片


圖4-9:析出常量NAME_KEY

Extract Field

Extract Field converts a local variable to a field (a.k.a. member) of your class.
Note You will need to import java.util.Date in order to create the proceding method without compile-time errors.
Define a method in your Sandbox class:
private Date getDate(){
return new Date();
}
<翻譯>

析出域

析出域將轉換一個本地變量到你的類域(a.k.a.成員變量)裏。
註意:為了創建和處理這個方法而不發生編譯錯誤,你必須導入android.os. Bundle
在你的Sandbox類裏定義一個方法:
private Date getDate(){
return new Date();
}

Place your cursor anywhere on Date (highlighted in bold) and press Ctrl+Alt+F | Cmd+Alt+F. You will see a dialog box like the one shown in Figure 4-10. In Android, the naming convention is to prefix fields (a.k.a. members) with an m. You will also notice a drop-down menu that allows you to initialize your field in the current method, the field declaration, or the constructor. Select Field Declaration and press Enter.
<翻譯>
把光標放到Date(粗體高亮)上並按鍵Ctrl+Alt+F | Cmd+Alt+F。你將看到一個對話框如圖4-10所示。在Android裏,按慣例域(a.k.a. 成員變量)名的頭字母用m。你將會註意到一個下拉菜單允許你初始化當前方法中的域,域聲明,或構造器。選擇域聲明並按回車。

技術分享圖片


圖4-10:析出域對話框

You should end up with something like this:
private final Date mDate = new Date();
...
private Date getDate(){
return mDate;
}
Remove the final keyword so the declaration line looks like the following code snippet:
private Date mDate = new Date();
<翻譯>
結果如下:
private final Date mDate = new Date();
...
private Date getDate(){
return mDate;
}
移除final關鍵字,結果這個域聲明如下:
private Date mDate = new Date();

Extract Parameter

Extract Parameter allows you to extract a variable and place it as a parameter of the enclosing method. Define a method in your Sandbox class:
private void setDate(){
mDate = new Date();
}
<翻譯>

析出參數

析出參數允許你析出一個變量並放到封套的方法裏。在你的Sandbox類裏定義一個方法:
private void setDate(){
mDate = new Date();
}

Place your cursor anywhere on Date() (highlighted in bold), press Ctrl+Alt+P | Cmd+Alt+P, and press Enter. The resulting method should look like the following code snippet:
private void setDate(Date date){
mDate = date;
}
<翻譯>
將光標放到Date()(粗體高亮)上,按Ctrl+Alt+P | Cmd+Alt+P接著按回車。結果這個方法如下代碼片段所示:
private void setDate(Date date){
mDate = date;
}

Extract Method

Extract Method lets you select one or more lines of contiguous code and place them in a separate method. There are two reasons you would want to do this. The first reason is that you have a method that is too complex. Breaking an algorithm into discrete blocks of approximately 10–20 lines each is much easier to read and far less error-prone than one method with 100 lines of code.
<翻譯>

析出方法

析出方法讓你選擇一行或多行行連續的代碼放到一個分離的方法中。有兩個原因你會想做這個。首先是方法太復雜了。相對於100行的代碼,打斷它到約10到20行的算法塊會比較容易閱讀且會較少錯誤。

It’s almost never a good idea to repeat a block of code, so if you find a block of code that is repeated, it’s best to extract a method and call that method in place of the repeated blocks. By extracting a method and calling it where you had previous used a repeated block of code, you can maintain your method in one place, and if you need to modify it, you need only modify it once. Re-create the following two methods in your Sandbox class, as shown in Listing 4-1. Feel free to copy and paste.
private String methodHello (){
String greet = "Hello";
StringBuilder stringBuilder = new StringBuilder();
for(int nC = 0; nC < 10; nC++){
stringBuilder.append(greet + nC);
}
return stringBuilder.toString();
}
private String methodGoodbye (){
String greet = "Goodbye";
StringBuilder stringBuilder = new StringBuilder();
for(int nC = 0; nC < 10; nC++){
stringBuilder.append(greet + nC);
}
return stringBuilder.toString();
}
<翻譯>
再者,重復的代碼從來就不是好主意,因而如果你發現了重復的代碼,最好析出它們成一個方法並在重復的地方調用它。通過析出之前重復的代碼到一個方法裏並調用它,你可以保留你的方法在一個地方,如果你想修改它,你只要修改一次。在你的Sandbox類裏重建下面的兩個方法如清單4-1。你可以自由地復制和粘貼。
清單4-1
private String methodHello (){
String greet = "Hello";
StringBuilder stringBuilder = new StringBuilder();
for(int nC = 0; nC < 10; nC++){
stringBuilder.append(greet + nC);
}
return stringBuilder.toString();
}
private String methodGoodbye (){
String greet = "Goodbye";
StringBuilder stringBuilder = new StringBuilder();
for(int nC = 0; nC < 10; nC++){
stringBuilder.append(greet + nC);
}
return stringBuilder.toString();
}

As we’ve already mentioned, any time you find yourself repeating blocks of code or copying and pasting a block of code, you should consider using Extract Method. Select all the lines highlighted in bold in Listing 4-1. Now press Ctrl+Alt+M | Cmd+Alt+M to extract the method. You will be presented with a dialog box showing the signature of the method. Rename this method to getGreet, as shown in Figure 4-11, and click OK.
<翻譯>
象我們已經提到過的,任何時候你發現重復一個代碼塊或復制和粘貼代碼塊,你就必須考慮析出方法了。選擇清單4-1中粗體高亮的塊。現在按Ctrl+Alt+M | Cmd+Alt+M析出方法。將呈現一個對話框列出方法的簽名。重命名這個方法為getGreet,如圖4-11所示,接著點擊OK。

技術分享圖片


圖4-11:析出方法對話框

Android Studio scans your file and sees that you have another instance of the exact block of code. Click Yes to accept the suggestions in the Process Duplicates dialog box, as shown in Figure 4-12.
<翻譯>
Android Studio掃描你的文件並看到你有另外一個確鑿的代碼塊案例。在處理復制對話框裏點擊Yes接受建議,如圖4-12所示。

技術分享圖片


圖4-12:復制處理對話框

You should end up with something like Listing 4-2. The resulting method is far easier to maintain now that it is kept in one place.
Listing 4-2. Code Resulting from Extract Method Operation
private String methodHello (){
String greet = "Hello";
return getGreet(greet);
}
private String methodGoodbye (){
String greet = "Goodbye";
return getGreet(greet);
}
private String getGreet (String greet){
StringBuilder stringBuilder = new StringBuilder();
for(int nC = 0; nC < 10; nC++){
stringBuilder.append(greet + nC);
}
return stringBuilder.toString();
}
<翻譯>
你將看到清單4-2的代碼。現在結果方法很容易保留在某個地方。
清單 4-2.從析出方法操作裏得出的結果代碼
private String methodHello (){
String greet = "Hello";
return getGreet(greet);
}
private String methodGoodbye (){
String greet = "Goodbye";
return getGreet(greet);
}
private String getGreet (String greet){
StringBuilder stringBuilder = new StringBuilder();
for(int nC = 0; nC < 10; nC++){
stringBuilder.append(greet + nC);
}
return stringBuilder.toString();
}

Advanced Refactoring

The refactoring operations presented throughout the remainder of this chapter are advanced. If you’re interested in simply getting up to speed with Android Studio, you already have sufficient knowledge to use the refactoring operations effectively, and you may skip this section. However, if you understand Java well and want to take a deep dive into some of the more advanced refactoring operations, continue reading.
<翻譯>

高級重構

整個這章所描述的剩下的其他重構操作是高級別的。如果你有興趣簡單迅速地提高Android Studio,已經有了足夠的知識來有效地使用重構操作,也許你可以跳過這節。但無論如何,如果你對JAVA有比較好的理解並且想鉆研更多的重構操作,繼續看下去吧。

Start with a clean slate by removing all method and members from Sandbox.java:
public class Sandbox {
}
Right-click (Ctrl-click on Mac) the com.apress.gerber.helloworld package in the Project tool window and choose New ? Java Class. Name your class Minibox. Change the definition of Minibox so that it inherits from Sandbox and has a member called mShovel, as shown here:
public class Minibox extends Sandbox {
private String mShovel;
}
<翻譯>
移除Sandbox.java裏的所有成員變量及方法,從一張白紙開始。
public class Sandbox {
}
右鍵點擊(Mac電腦用Ctrl+點擊)Project tool窗口裏的com.apress.gerber.helloworld包,選擇New ? Java Class。命名這個類為Minibox。修改Minibox類定義繼承自Sandbox並且有個成員變量叫做mShovel,如這裏所示:
public class Minibox extends Sandbox {
private String mShovel;
}

Push Members Down and Pull Members Up

Pushing members down and pulling members up is used with inheritance. Notice that we have defined the mShovel member in the Minibox class. Let’s assume we decide later that mShovel may be useful for other classes that extend Sandbox. To do this, open the Minibox class and choose Refactor ? Pull Members Up. The resulting dialog box looks like Figure 4-13.
<翻譯>

推高成員變量以及拉低成員變量

推高成員變量以及拉低成員變量用於繼承。註意到我們定義了一個mShovel成員變量在Minibox類裏。讓我們假設mShovel可能對於其他繼承自Sandbox類的子類也有用。這樣做,打開Minibox類並選擇Refactor ? Pull Members Up。結果對話框如圖4-13所示。

技術分享圖片


圖 4-13: 推高成員變量對話框

The mShovel member is selected by default and the Pull Up Members combo box is set to the com.apress.gerber.helloworld.Sandbox class by default since Sandbox is the superclass of Minibox. Click Refactor. If you now inspect Sandbox and Minibox, you will notice that the mShovel member belongs to Sandbox and is no longer present in Minibox. As a general rule, if you believe that a member may be useful to other extending classes, you should pull those members up the hierarchy. To push members down the hierarchy, you can follow similar steps.
<翻譯>
mShovel會被缺省地選中,並且因為Sandbox是Minibox的父類所以推高成員變量組合窗口會缺省地設定在com.apress.gerber.helloworld.Sandbox類上。點擊Refactor,檢視Sandbox和Minibox,你將發現mShovel成員變量不再出現在Minibox裏了,而屬於Sandbox。作為一般規則,如果你覺得一個成員變量對其他擴展類也是有用的,那麽就把這些成員變量在繼承層次裏推高。用類似的手法可以拉低成員變量。

Replace Inheritance with Delegation

Right-click (Ctrl-click on Mac) the com.apress.gerber.helloword package and choose New ? Java Class. Name your class Patio and make it extend Sandbox:
public class Patio extends Sandbox {
}
<翻譯>

解除繼承並委托成員變量

右鍵點擊(Mac電腦用Ctrl+點擊)com.apress.gerber.helloword包選擇New ? Java Class。命名這個新類為Patio並繼承自Sandbox:
public class Patio extends Sandbox {
}

Upon further analysis, we decide that Patio is not a Sandbox, but rather has a Sandbox. To change this relationship, navigate to Refactor ? Replace Inheritance with Delegation. In the resulting dialog box, click the Generate Getter for Delegated Component check box, shown in Figure 4-14.
<翻譯>
進一步分析後,我們決定Patio不是一個Sandbox,但更象是它擁有一個Sandbox。為了改變它們的關系,導航到Refactor ? Replace Inheritance with Delegation。在結果對話框裏,點擊為委托成產生getter方法,如圖4-14所示。

技術分享圖片


圖 4-14:解除繼承並委托成員變量對話框

Your Patio class should now have a Sandbox member, as shown in the following code snippet:
public class Patio {
private final Sandbox mSandbox = new Sandbox();
public Sandbox getSandbox() {
return mSandbox;
}
}
<翻譯>
現在你的Patio類將擁有一個Sandbox成員變量,如下代碼片段所示:
public class Patio {
private final Sandbox mSandbox = new Sandbox();
public Sandbox getSandbox() {
return mSandbox;
}
}

Encapsulate Fields

Encapsulation is an object-oriented strategy that hides class members by making their access level private and then provides a public interface to those members via public getter/setter methods. Refactor ? Encapsulate Fields is similar to Code ? Generate ? Getter and Setter, though you have a lot more options when you choose Refactor ? Encapsulate Fields. Open your Sandbox class and define a new member called mChildren, as highlighted in bold
in the next code snippet. From the main menu, choose Refactor ? Encapsulate Fields.
public class Sandbox {
private String mShovel;
private int mChildren;
}

封裝域

<翻譯>
封裝域是一種面向對象策略,通過使訪問級別為私有來隱藏類成員變量並提供以公開的getter/setter方法作為公開的接口。盡管當你選擇Refactor ? Encapsulate Fields時有很多的選擇,但Refactor ? Encapsulate Fields類似於Code ? Generate ? Getter and Setter。打開你的Sandbox類並定義一個成員變量叫mChildren,如下面代碼片段中的粗體高亮部分。從主菜單,選擇Refactor ? Encapsulate Fields。
public class Sandbox {
private String mShovel;
private int mChildren;
}

The resulting dialog box allows you to choose exactly how your fields will be encapsulated and what access level they should have. A truly encapsulated field will have private visibility with public accessor (getter) and mutator (setter) methods. Click the Refactor button, shown in Figure 4-15, and notice that Android Studio has generated getters and setters for us in our Sandbox.java class.
<翻譯>
結果對話框允許你精確地選擇怎樣封裝這些域以及它們的訪問級別。真正地封裝域將有一個私有的可視度及公有的訪問(getter)及改變(setter)方法。點擊Refactor按鈕,如圖4-15所示,註意到Android Studio在我們的Sandbox.java類裏為我們生成所有的getter和setter。

技術分享圖片


圖 4-15:封裝域對話框

Wrap Method Return Value

Wrapping a return value may be useful when you need to return an object rather than a primitive (though there are other scenarios where you might want to wrap a return value). Place your cursor on the getChildren() method and navigate to Refactor ? Wrap Method Return Value. Select the Use Existing Class check box and type java.lang.Integer as the Name and value as the Wrapper Field, as shown in Figure 4-16. Now click Refactor and notice that your getChildren() method returns an Integer object rather than a primitive int.
<翻譯>

包裝方法的返回值類型

當你需要返回一個對象而不是基本數據類型時,包裝返回值可能是有用的(當然還有其他的情形你可能想包裝一個返回值)。把光標放到getChildren()方法上並導航到Refactor ? Wrap Method Return Value。選擇Use Existing Class選項,名稱框輸入java.lang.Integer,包裝域框則選擇value,如圖4-16所示。現在點擊Refactor按鈕且註意到你的getChildren()方法返回一個Integer類,而不是基本數據類型int。

技術分享圖片


圖 4-16: 包裝返回值對話框

Replace Constructor with Factory Method

Place your cursor inside the enclosing brackets of the Sandbox class definition. Press Alt+Insert | Cmd+N and select Constructor to generate a new constructor. Choose both members, shown in Figure 4-17, and click OK.
<翻譯>

用工廠方法代替構造器

把光標放在Sandbox類定義附欄內。按Alt+Insert | Cmd+N接著選擇生成一個新構造器。選擇所有成員變量,如圖4-17所示,然後點擊OK。

技術分享圖片


圖 4-17:通過構造器來選擇域的對話框

Place your cursor anywhere in the newly defined constructor, shown in the following code snippet, and then navigate to Refactor ? Replace Constructor with Factory Method. The resulting dialog box looks like Figure 4-18. Click Refactor to generate a factory method.
public Sandbox(String shovel, int children) {
mShovel = shovel;
mChildren = children;
}
<翻譯>
將光標放到如下所示代碼片段構造器的任何位置,並導航到Refactor ? Replace Constructor with Factory Method。結果對話框象圖4-18所示。點擊Refactor來生成一個工廠方法。
public Sandbox(String shovel, int children) {
mShovel = shovel;
mChildren = children;
}

技術分享圖片


圖 4-18: 用工廠模式代替構造器的對話框

Notice that the constructor is now private and that a new static method returns an instance of the Sandbox class, as shown in the following code snippet. This operation is particularly useful if you are creating a singleton.
public static Sandbox createSandbox(String shovel, int children) {
return new Sandbox(shovel, children);
}
<翻譯>
註意到之前的構造器現在變成private了並且一個新的靜態方法返回Sandbox類的實例,如下面代碼片段所示。如果你正創建一個單例類,這將會是非常有用的。
public static Sandbox createSandbox(String shovel, int children) {
return new Sandbox(shovel, children);
}

Convert Anonymous to Inner

In the constructor of your Sandbox class, add the following line:
new Thread(new Runnable()).start();
<翻譯>

轉換匿名內部類

在你的Sandbox類的構造器裏加上下面行:
new Thread(new Runnable()).start();

Place your cursor on Runnable() and press Alt+Enter to invoke the code-completion operation. Then select Implement Methods. Select the run method and click OK. Your code should look something like the following code snippet:
new Thread(new Runnable() {
@Override
public void run() {
//do something
}
}).start();
<翻譯>
把光標放在Runnable()上並按下Alt+Enter來調用完成代碼操作。然後選擇實現方法。選擇run()方法並點擊OK。你的代碼將象下面片段所示:
new Thread(new Runnable() {
@Override
public void run() {
//do something
}
}).start();

Place your cursor on Runnable() and navigate to Refactor ? Convert Anonymous to Inner. Android Studio suggests MyRunnable as a class name for you, as shown in Figure 4-19. Deselect the Make Class Static check box and click OK. Notice that you now have a private inner class called MyRunnable in Sandbox.java that implements the Runnable interface. This example doesn’t do much; however, you may have opportunities to use this operation when delegating the behaviors of Views.
把光標放在Runnable()上並導航到Refactor ? Convert Anonymous to Inner。Android Studio建議MyRunnable作為這個類名,如圖4-19所示。去選Make class static選項後點擊OK。註意到你將在Sandbox類裏得到一個私有的內部類叫MyRunnable,它實現Runnable接口。這個例子沒有做更多的事;不管怎樣,當委派View的行為時你也許有機會用到這個。

技術分享圖片


圖 4-19: 轉換匿名內部類的對話框

Summary

This chapter discussed many of the refactoring operations available in Android Studio. Refactoring code is a necessary part of any programming project, and the refactoring tools in Android Studio are among the best. Android Studio mitigates the risk of performing certain refactoring operations by analyzing the consequences and allowing you to preview the results in the Find tool window prior to committing an operation. The most important refactoring operations are available from the Refactor ? Refactor This dialog box, which is invoked by using the keyboard shortcut Ctrl+Alt+Shift+T | Ctrl+T.
<翻譯>

小結

這章討論了Android Studio目前有效的許多重構操作。重構代碼是編程工程的一個必需的部分,Android Studio裏的重構工具是最好的重構工具之一。Android Studio通過分析推理以及允許你於提交操作前在Find tool窗口預覽結果,減低了某些操作執行的風險。最重要的是重構操作Refactor ? Refactor This對話框是如此有效的,這個可以通過用快捷鍵Ctrl+Alt+Shift+T | Ctrl+T來調用。

第四章:重構代碼[學習Android Studio漢化教程]