Automatic refactoring implementation in Eclipse explore _jsp programming

Source: Internet
Author: User
Tags instance method

This article uses Eclipse's automatic refactoring to refactor an instance of a program to explore the extent to which eclipse automatic refactoring can assist in refactoring the process. Example of a program instance using the book refactoring:improving the design of Existing code.

Eclipse's automatic refactoring capability supports renaming of various program elements and automatically updates related references. Eclipse can support methods, fields move between classes, and automatically update references. Eclipse better supports inline fields, update replacements for functions. Eclipse better supports program elements such as extraction methods, variables, and so on.

The process of refactoring is an ongoing process of experimentation and exploration. Eclipse refactoring supports undo and redo, and the ability to preview refactoring results is a useful feature.

Eclipse's renaming, extracting methods, moving, inline, changing method features, and so on, are more mature and worth using. As for the refactoring of the design structure, Eclipse is not well supported. However, the author believes that the concept of automatic reconstruction should be "tool-assisted reconstruction work", and people still undertake most of the reconstruction work.

  First, preparatory work

This article uses the example in chapter one of the book "Refactoring:improving The Design of Existing code". The code before refactoring and the code to refactor each step are shown in the attachment. Readers are best to read this article in conjunction with the book refactoring:improving the design of Existing code.

Eclipse uses the following version:


The Chinese language pack is also installed.

  Second, the reconstruction of the first step: decomposition and reorganization of statement ()

Objective:

1, the Swich statement in the statement () function is refined into a separate function amountfor ().

2, modify amountfor () parameter naming

Refactoring method:

Extract method
Rename method

Method:

1. Select the code block of the Swich statement, select "Refactor/Extract Method" In the right-click menu, and the Parameter dialog box appears. Eclipse automatically analyzes the local variables in the code block and finds two local variables: each and thisamount. Where each is read only in a block of code, but Thisamount is modified in the code block. According to the rules summarized by refactoring extract method, we should treat each as the parameter of the extraction function and Thisamount as the return value of the extraction function. However, Eclipse does not differentiate between these two variables as a parameter to extract the new method, as shown in the diagram.


Our aim is to use each parameter that will not be modified in the extraction function, and the modified Thisamount as the return value. The solution is to double thisamount = 0; This line of code moves to the top of the switch statement, and becomes this:

Double thisamount = 0;
Switch (Each.getmovie (). Getpricecode ()) {
Case Movie.regular:
Thisamount + 2;
if (each.getdaysrented () >2)
Thisamount + = (each.getdaysrented ()-2) *1.5;
Break

Case Movie.new_release:
Thisamount + + each.getdaysrented () *3;
Break

Case Movie.childrens:
Thisamount + 1.5;
if (each.getdaysrented () >3)
Thisamount + = (each.getdaysrented ()-3) *1.5;
Break
}

With this code selected and the "Refactor/Extract Method" selected in the right-click menu, eclipse has become smarter this time, as pictured.

Selecting the Preview button in advance to see the results of the refactoring is consistent with our initial purpose.


Select the "OK" button, after the refactoring of the Code fragment as follows:

Public String statement () {
Double TotalAmount = 0;
int frequentrenterpoints = 0;
Enumeration rentals = _rentals.elements ();
String result = "Rental record for" + getName () + "";

while (Rentals.hasmoreelements ()) {
Rental each = (rental) rentals.nextelement ();

Double thisamount = amountfor (each);

Frequentrenterpoints + +;
if ((Each.getmovie (). Getpricecode ()) ==movie.new_release &&each.getdaysrented () >1)
Frequentrenterpoints + +;

result = = "" + Each.getmovie () getTitle () + "" +string.valueof (Thisamount) + "";
TotalAmount + = Thisamount;
}

result = = "Amount owed is" + string.valueof (TotalAmount) + "";
result = = "you earned" + string.valueof (frequentrenterpoints) + "frequent renter points";

return result;
}

/**
* @param each
* @return
*/
Private double amountfor (rental each) {
Double thisamount = 0;
Switch (Each.getmovie (). Getpricecode ()) {
Case Movie.regular:
Thisamount + 2;
if (each.getdaysrented () >2)
Thisamount + = (each.getdaysrented ()-2) *1.5;
Break

Case Movie.new_release:
Thisamount + + each.getdaysrented () *3;
Break

Case Movie.childrens:
Thisamount + 1.5;
if (each.getdaysrented () >3)
Thisamount + = (each.getdaysrented ()-3) *1.5;
Break
}
return thisamount;
}

2, select the parameters of Amountfor () each, in the right-click menu, choose Refactor/Rename, enter a new name in the dialog box: arental, select OK, amountfor () all the references to each are replaced with the new name. Modify the local variable in amountfor () Thisamount to result in the same way. The Amountfor () code after the refactoring is as follows:

/**
* @param arental
* @return
*/
Private double amountfor (rental arental) {
Double result = 0;
Switch (Arental.getmovie (). Getpricecode ()) {
Case Movie.regular:
result = 2;
if (arental.getdaysrented () >2)
result = = (arental.getdaysrented ()-2) *1.5;
Break

Case Movie.new_release:
result = = arental.getdaysrented () *3;
Break

Case Movie.childrens:
result = 1.5;
if (arental.getdaysrented () >3)
result = = (arental.getdaysrented ()-3) *1.5;
Break
}
return result;
}

  third, refactoring the second step: Move the "Amount calculation" code

Objective:

1, the function amountfor () transferred to the rental class, and renamed to Getcharge ().

2, update and replace all references to Amountfor ().

Refactoring method:

Move method
Change Method Signatrue
Inline method
Inline Temp

Method:

1, the definition of the selected function Amountfor (), select "Refactor/move" in the right key menu, display the Parameter setup dialog box. Change the name of the new method to Getcharge. Pressing the "OK" button, the Amountfor () function in the Customer class is moved to the rental class and renamed to: Getcharge ().


Also, Eclipse automatically adds a row of "delegate" code to the new function in the customer's Amountfor () function:

Private double amountfor (rental arental) {
return Arental.getcharge ();
}

This line of code produces a compilation error because the private type of amountfor () is passed to the new method:

/**
* @param this
* @return
*/
Private double Getcharge () {
......
}

2, continue to refactor! Select the Getcharge () method, select Refactor/Change method feature in the right-click menu, eject the Parameter selection dialog box, and change the access modifier from private to public. The eclipse's compile error prompt disappears automatically.


3. Back to the customer class, replace all references to Amountfor () with a reference directly to Getcharge (). Select the function amountfor (rental arental) of the customer class, select refactor/Inline in the right-click menu, and the Parameter selection dialog box appears.


Select the "Confirm" button where the reference to Amountfor () is replaced with a reference to Getcharge ().

Public String statement () {
......
Double thisamount = Each.getcharge ();
......
}

4, remove the temporary variable Thisamount.

Select the variable thisamount, in the right-click menu, select "Refactoring/inline", refactoring preview window as follows, can be seen to achieve the purpose of refactoring. Press the "Confirm" button to refactor the code.


Statement () Code:

Public String statement () {
Double TotalAmount = 0; Total consumption amount
int frequentrenterpoints = 0; Frequent product points
Enumeration rentals = _rentals.elements ();
String result = "Rental record for" + getName () + "";

while (Rentals.hasmoreelements ()) {
Rental each = (rental) rentals.nextelement (); Get a loan record

Add frequent renter points (cumulative frequent product point)
Frequentrenterpoints + +;
Add Bouns for a two day new release rental
if ((Each.getmovie (). Getpricecode ()) ==movie.new_release && each.getdaysrented () >1)
Frequentrenterpoints + +;

Show figures to this rental (display this loan data)
result = "" + Each.getmovie (). GetTitle () + "" +
String.valueof (Each.getcharge ()) + "";
TotalAmount + + each.getcharge ();
}

Add footer lines (end printing)
result = = "Amount owed is" + string.valueof (TotalAmount) + "";
result = = "you earned" + string.valueof (frequentrenterpoints) + "frequent renter points";

return result;
}
  
   Iv. Refactoring The third step: refining the "frequent product point calculation" code

Objective: To extract the "Frequent product point calculation" code and put it in the rental class, "Frequent product point calculation" code is as follows.

Public String statement () {
......
Add frequent renter points
Frequentrenterpoints + +;
Add Bouns for a two day new release rental
if ((Each.getmovie (). Getpricecode ()) ==movie.new_release && each.getdaysrented () >1)
Frequentrenterpoints + +;
......
}

The code after the refactoring is as follows:

Frequentrenterpoints + + each.getfrequentrenterpoints ();

Refactoring method:

Extract method
Move method
Change Method Signatrue
Inline method

Method:

1, first, the extraction of code into a separate function.

Refactoring code with "Extract Method", Function name: Getfrequentrenterpoints. Unfortunately, Eclipse's inability to generate such things as: Frequentrenterpoints + = getfrequentrenterpoints (rental arental); The code. The reason is that the local variable frequentrenterpoints to perform the self augmentation is to be present on the right side of the equation, so the extraction function getfrequentrenterpoints () must take frequentrenterpoints as an argument. Manually modify the function and reference to the function, after refactoring the following code:

Public String statement () {
......
while (Rentals.hasmoreelements ()) {
......
Frequentrenterpoints + + getfrequentrenterpoints (each);
......
}
......
}

/**
* @param each
* @return
*/
private int getfrequentrenterpoints (rental each) {
if ((Each.getmovie (). Getpricecode ()) ==movie.new_release && each.getdaysrented () >1)
return 2;
Else
return 1;
}

2. Move the Getfrequentrenterpoints () to the rental class.

3. Getfrequentrenterpoints () "Change method feature" is public.

4, the customer's function getfrequentrenterpoints () to perform inline operation, refactoring target completed.

   v. Refactoring step Fourth: Removing temporary variables (totalamount and frequentrenterpoints)

Objective: To remove temporary variables (totalamount and frequentrenterpoints)

Method:

1. The definition and reference structure of the analysis TotalAmount and frequentrenterpoints are as follows:

Declarations and definitions
Double TotalAmount = 0;
int frequentrenterpoints = 0;
......
modifying in Loops
while (Rentals.hasmoreelements ()) {
......
Frequentrenterpoints + + each.getfrequentrenterpoints ();
......
TotalAmount + + each.getcharge ();
......
}
......
Use outside the loop
result = = "Amount owed is" + string.valueof (TotalAmount) + "";
result = = "you earned" + string.valueof (frequentrenterpoints) + "frequent renter points";
......

The above two variables are defined and used outside the loop body and are modified in the loop, and using the Replace Temp with Query method to remove the two temporary variables is a slightly more complex refactoring. Unfortunately, Eclipse does not currently support such refactoring.

2, manual modification of the code.

   Vi. reconstructing the fifth step: using polymorphism to replace price-related conditional logic

Objective:

1, move the function Getcharge () in the rental class to the movie class.

2, move the function getfrequentrenterpoints () in the rental class to the movie class.

Refactoring method:

Move method
Inline method

Method:

1, select the function in the rental Class Getcharge (), right-click menu selected "Refactor/move", eclipse hint cannot find the receiver, cannot move. The reason is this line statement:

Switch (Getmovie (). Getpricecode ()) {//Get movie rental price

Check Getmovie (), right-click the menu to select Refactor/inline, and make sure the code becomes:

Switch (_movie.getpricecode ()) {//Get movie rental price

When Getcharge () is selected, the function is moved to the movie class after the refactoring/move is performed. However, this was only partially achieved, and we found that the moved code passed the rental as a parameter to Getcharge (), modified manually, and the code became:

Class Movie ...
/**
* @param this
* @return
*/
public double getcharge (int _daysrented) {
Double result = 0;
Switch (Getpricecode ()) {//Get movie rental price
Case Movie.regular://Ordinary film
result = 2;
if (_daysrented>2)
result = = (_daysrented-2) *1.5;
Break

Case Movie.new_release://new film
result = _daysrented*3;
Break

Case Movie.childrens://Children's film
result = 1.5;
if (_daysrented>3)
result = = (_daysrented-3) *1.5;
Break
}
return result;
}

Class rental ...
/**
* @param this
* @return
*/
Public double Getcharge () {
Return _movie.getcharge (_daysrented);
}

2, with the same steps to deal with Getfrequentrenterpoints (), Refactoring code:

Class Movie ...
/**
* @param frequentrenterpoints
* @param this
* @return
*/
public int getfrequentrenterpoints (int daysrented) {
if ((Getpricecode ()) ==movie.new_release && daysrented>1)
return 2;
Else
return 1;
}
Class rental ...
/**
* @param frequentrenterpoints
* @param this
* @return
*/
public int getfrequentrenterpoints (int daysrented) {
if ((Getpricecode ()) ==movie.new_release && daysrented>1)
return 2;
Else
return 1;
}

   Seven, refactoring the sixth step: finally ... We came to inherit

Objective: To introduce the state pattern to the switch statement.

Method:

It's a pity that we have to end this eclipse's automatic refactoring trip ahead of time. Eclipse can hardly do structural refactoring. Perhaps Martin Fowler in the book The Automatic Refactoring tool stops at the "tool-assisted refactoring work" concept. Art is the patent of mankind, the dream of programming art will continue.

Interested readers can view the last step of the manual refactoring Code. Will refactor to the end!

Appendix: Eclipse Supported Refactoring Method (excerpt from Eclipse Chinese help)

Name feature
Undo the undo that performed the last refactoring. The refactoring undo buffer is valid as long as no other source changes have been performed except for refactoring.
Redo performs the redo of the last undo refactoring. The refactoring Undo/redo Buffer is valid as long as no other source changes have been performed except for refactoring.
Renames the Start Rename Refactoring dialog box: renames the selected element and corrects all references to the element (if enabled) (also in other files). Can be used for: methods, fields, local variables, method parameters, types, compilation units, packages, source folders, and items, and a text selection that resolves to one of these element types.
Move launches the Move Refactoring dialog box: Moves the selected element and corrects all references to the element (if enabled) (also in other files). Applies to an instance method (which can be moved to a component), one or more static methods, static fields, types, compilation units, packages, source folders, and items, and a text selection that resolves to one of these element types.
Change the method feature to start the Change Method feature refactoring dialog box. Change the parameter name, parameter type, and parameter order, and update all references to the corresponding method. In addition, you can drop or add parameters, and you can change the method return type and its visibility. You can apply this refactoring to a method or to a text selection that resolves to a method.
Converts an anonymous class to a nested class launches the "Convert anonymous class to nested class" refactoring dialog box. Helps you convert an anonymous inner class to a member class. You can apply this refactoring to anonymous inner classes.
Converts a nested type to a top-level start "convert a nested type to a top-level type" refactoring dialog box. Create a new Java compilation unit for the selected member type and update all references as needed. For non-static member types, fields are added to allow access to previous peripheral instances. You can apply this refactoring to a member type or to text that resolves to a member type.
Push down to start the Push down refactoring dialog box. Moves a set of methods and fields from one class to its subclass. You can apply this refactoring to one or more methods and fields that are declared in the same type or to a text selection within a field or method.
One or more of the methods, fields, and member types declared in the pull-back configuration can also be applied to text selections within a field, method, or member type. Wizard. Move a field or method to a superclass of its declaring class or (for a method) declare a method as an abstract class in a superclass. You can apply this refactoring to the same class
The extraction interface initiates the Extract Interface Refactoring dialog box. Use a set of methods to create a new interface and enable the selected class to implement the interface, as much as possible to change the reference to the class to a reference to the new interface (optional). You can apply this refactoring to types.
Start the use Super type as much as possible dialog box using the superclass whenever possible. Replace the occurrence of a type with one of its super types, before performing this substitution, you need to identify all possible locations for this substitution. This refactoring can be used for types.
Inline starts the inline Refactoring dialog box. Inline local variables, methods, or constants. This refactoring can be used for methods, static final state fields, and text selections that resolve to methods, static final state fields, or local variables.
The extraction method launches the Extract Method Refactoring dialog box. Creates a new method that contains the currently selected statement or expression, and replaces the selection with a reference to the new method. You can use the expand Selection in the Edit menu to get a valid selection. This feature is useful for cleaning up long, messy, or overly complex methods.
Extracts local variables to start the Extract Variable Refactoring dialog box. Creates a new variable that is specified for the currently selected expression and replaces the selection with a reference to the new variable. This refactoring can be used to resolve text selections that are local variables. You can use the expand Selection in the Edit menu to get a valid selection.
The extract constants start the Extract Constants Refactoring dialog box. Creates a static final field from the selected expression and replaces the field reference, and optionally overrides other occurrences of the same expression. This refactoring can be used for static final state fields and text selections that resolve to static final state fields.
Converts a local variable to a field starts the Convert local variable to field refactoring dialog box. Converts a local variable to a field. If the variable is initialized at creation time, this action moves the initialization to the declaration of the new field or the constructor of the class. This refactoring can be used to resolve text selections that are local variables.
Encapsulate Field launches the Self-Encapsulation Field refactoring dialog box. Replaces all references to the field with the Getting and setting methods. It applies to the selected field or to a text selection that resolves to a field.
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.