Rebuilding notes -- refining functions and restructuring refining Functions
This article is in the study of the summary, welcome to reprint but please note the Source: http://blog.csdn.net/pistolove/article/details/42214393
In the first three articles, I introduced the refactoring entry, the bad taste of the Code (I), and the bad taste of the Code (I ). This article will officially start the reconstruction journey. From the beginning of this article, 92 reconstruction methods will be introduced in subsequent articles, each of which will correspond to a bad taste of code. In the process of introduction, each refactoring method will also correspond to an article. Some refactoring methods may be relatively short, but they will be listed as one article separately for ease of organization. (PS: In any case, I will always share these refactoring methods with you. I think there will always be people who will benefit from them and hope to help you)
Let's take a look at the refactoring method of "refining functions.
Open door
Discovery: You have a piece of code that can be organized together and independent.
Solution: Put This code into an independent function and ask the function name to explain the purpose of the function.
Before reconstruction:
public void PrintOwing(double amount) {printBanner();// printdetailSystem.err.println("name: " + _name);System.err.println("amount: " + amount);}
After reconstruction:
public void PrintOwing(double amount) {printBanner();printDetails(amount);}private void printDetails(double amount) {System.err.println("name: " + _name);System.err.println("amount: " + amount);}
Motivation
Refining functions are one of the most common refactoring techniques. When we see a function that is too long or a code that requires comments to make people understand its purpose, we should refactor it and put the code into an independent function.
We all like short and well-named functions. There are three main reasons: First, if each function has a small granularity, the chance of function reuse will be greater; second, it will make the high-level function read like a series of comments, easy to understand. Third, if the functions are all fine-grained, the function can be more easily rewritten.
You may ask, how long is a function suitable? For refactoring, the length is not a problem. The key lies in the semantic distance between the function name and the function question. If refining can enhance the Definition of the code, it is worth doing, even if the function name is longer than the extracted code.
Method (1) create a new function and name it according to the function intent. (2) copy the extracted code from the source function to the new target function. (3) carefully check the extracted code and refer to the variable with the scope limited to the original function (including local variables and source function parameters ). (4) check whether there are temporary variables for "extracted code segments only. If yes, declare it as a temporary variable in the target function. (5) Check the extracted code segment to see if any value of the local variable is changed. If a temporary variable value is modified, check whether it can process the extracted code segment as a query and assign the result to the relevant variable. If there are multiple variables that are difficult to do or are modified, you need to use "break down the temporary variables" or replace the temporary variables with a query "for processing and then try to extract them. (6) Pass the local variables to be read in the extracted code segment as parameters to the target function.
(7) Compile after processing all local variables.
(8) after successful programming, replace the extracted code segment with the call to the target function in the source function.
(9) test.
Example
A: No local variables
In the simplest case, refining functions are as easy as possible:
// Public void PrintOwing () {Enumeration e = _ orders. elements (); double outstanding = 0.0; // print bannerSystem. err. println ("************************************" ); system. err. println ("***************** OK ******************"); system. err. println ("************************************" ); // caculate outstandingwhile (e. hasMoreElements () {Order each = (Order) e. nextElement (); outstanding + = each. getAmout ();} // print detailsSystem. err. println ("name:" + _ name); System. err. println ("amout:" + outstanding );}
// Public void PrintOwing () {Enumeration e = _ orders. elements (); double outstanding = 0.0; printBanner (); // caculate outstandingwhile (e. hasMoreElements () {Order each = (Order) e. nextElement (); outstanding + = each. getAmout ();} // print detailsSystem. err. println ("name:" + _ name); System. err. println ("amout:" + outstanding);} private void printBanner () {// print bannerSystem. err. println ("************************************" ); system. err. println ("***************** OK ******************"); system. err. println ("************************************" );}
B: There are local variables.
The difficulty of This refactoring method is that when there are local variables, including the parameters passed into the source function and the temporary variables declared by the source function. Because the scope of local variables is limited to the source function, it takes extra effort to process these variables. In some cases, local variables cannot be reconstructed. A simple scenario is that the extracted code segment only reads the values of these variables without modifying them. In this case, they can be passed as parameters to the target function.
// There is a local variable public void PrintOwing () {Enumeration e = _ orders. elements (); double outstanding = 0.0; printBanner (); // caculate outstandingwhile (e. hasMoreElements () {Order each = (Order) e. nextElement (); outstanding + = each. getAmout ();} printDetails (outstanding);} private void printDetails (double outstanding) {System. err. println ("name:" + _ name); System. err. println ("amout:" + outstanding );}
C: assign a value to a local variable.
If the extracted code segment is assigned a value to the local variable, the problem becomes complicated. Only temporary variables are discussed here. Case 1: This variable is only used in the extracted code segment. In this case, the variable declaration is directly moved to the extracted code.
// Extract the calculation function public void PrintOwing () {printBanner (); double outstanding = getOutstanding (); printDetails (outstanding);} private double getOutstanding () {Enumeration e = _ orders. elements (); double outstanding = 0.0; while (e. hasMoreElements () {Order each = (Order) e. nextElement (); outstanding + = each. getAmout ();} return outstanding ;}
Case 2: code other than extracted Code also uses this variable. There are two cases: (1) if the variable is not used after the extracted code segment, you only need to modify it in the target function. In the following code, the Enumeration variable e is only used in the extracted code segment, so it can be moved to the new function.
private double getOutstanding() {Enumeration e = _orders.elements();double result = 0.0;while (e.hasMoreElements()) {Order each = (Order) e.nextElement();result+= each.getAmout();}return result;}
(2) If the variable is used after the extracted code segment, the target function must return the value after the variable is changed. In the following code, the double variable outstanding is used inside and outside the extracted code segment. Therefore, the new function must be returned.
// Public void PrintOwing (double previusamount) {Enumeration e = _ orders. elements (); double outstanding = previusamount * 1.5; printBanner (); // caculate outstandingwhile (e. hasMoreElements () {Order each = (Order) e. nextElement (); result + = each. getAmout ();} printDetails (outstanding );}
// Public void PrintOwing (double previusamount) {double outstanding = previusamount * 1.5; printBanner (); outstanding = getOutstanding (outstanding); printDetails (outstanding );} private double getOutstanding (double initialValue) {double result = initialValue; while (e. hasMoreElements () {Order each = (Order) e. nextElement (); result + = each. getAmout ();} return result ;}
After compilation and testing, sort out the Code as follows:
// Final adjustment public void PrintOwing (double previusamount) {printBanner (); outstanding = getOutstanding (previusamount * 1.5); printDetails (outstanding );}
This article mainly introduces refactoring techniques-refining functions, and briefly introduces different situations. The examples in this article are relatively simple and easy for those who have just learned. However, if there are too many temporary variables, the extraction may be difficult. At this time, we need to consider using other refactoring techniques for processing. After learning a number of refactoring techniques, I think you must understand how to use them. In short, this article will be helpful to you. For example, you have only one thing for a piece of code and are not affected by other codes, then we can use the refactoring method in this article to extract it into an independent function.
Finally, I hope this article will help you. If you have any questions, please leave a message. Thank you. (PS: the next article will introduce refactoring notes-inline functions)