"Refactoring and Improving the Design of Existing Code 2" Reorganize functions and data

/**
 @startTime 2020-12-20 15:30
 @endTime 2020-12-20 21:00
 @startPage 103 
 @endPage 130
 @efficiency 130/5 = 26页/天
 @needDays 412/26 = 16天
 @overDay 2020-12-16 + 16天 = 2020-12-31
*/

Chapter 5 Refactoring List

Chapters 5 to 12 constitute a draft of the refactoring list, the refactoring techniques listed in it come from the author's years of programming experience.

1. Reconstructed record format

  1. The first is the name. To build a refactoring vocabulary, the name is very important.
  2. After the name is a brief summary (summary). Briefly introduce the applicable scenarios of this refactoring technique and what it does. This part can help you find the refactoring techniques you need faster.
  3. Motivation introduces you to "why you need this refactoring" and "under what circumstances should you not use this refactoring".
  4. Methods (mechanics) concise step by step instructions on how to perform this refactoring.
  5. Examples show a very simple example of how this refactoring technique works.

2. Find reference points

Don't blindly search-replace, you should check every reference point to make sure it points to what you want to replace.
You can let the compiler help you capture the reference point, but this also has some problems, such as:

  1. If the deleted part is declared more than once in the inheritance system, the compiler will be confused.
  2. The compiler may be too slow.
  3. The compiler cannot find the reference point obtained through the reflection mechanism

3. How mature are these reconstruction techniques

Advance in small steps and test frequently.
Design patterns provide goals for refactoring.
There is an innate relationship between pattern and reconstruction. Pattern is the goal you want to achieve, and reconstruction is the way to reach.

Chapter 6 Reorganize Functions

A large part of my refactoring method is to organize functions to make them more appropriately package code.

1. Refine function

Put a piece of code in an independent function and let the function name explain the purpose of the function.
"motivation"

  1. If the granularity of each function is very small, the chance of the function being reused will be great;
  2. Make high-level functions read like a series of comments;
  3. If the functions are fine-grained, it will be easier to overwrite the
    functions ; how long is a suitable function? In my opinion, length is not a problem, the key lies in the semantic long sentences between the function name and the function body. If refinement can enhance the clarity of the code, then do it, even if the function name is longer than the refined code, it does not matter.

2. Inline function

Insert the function body at the function call point, and then remove the function.

3. Inline temporary variables

Replace all references to the variable with the expression itself that is assigned to it.

4. Replace temporary variables with queries

Distill this expression into an independent function, and replace all reference points of this temporary variable with calls to the new function. After that, the new function can be used by other functions.

5. Introduce explanatory variables

Put the result of a complex expression into a temporary variable, and use the variable name to explain the purpose of the expression.
"Motivation"
In conditional logic, introducing explanatory variables is particularly valuable. You can use this reconstruction to extract each conditional clause and use a well-named temporary variable to explain the meaning of the corresponding conditional clause. Another use of this reconstruction is that in longer algorithms, temporary variables can be used to explain the meaning of each step.

6. Decompose temporary variables

For each assignment, an independent and corresponding temporary variable is created.
"Motivation"
If temporary variables are assigned more than once, it means that they have assumed more than one responsibility in the function. If a temporary variable bears multiple responsibilities, it should be replaced with multiple temporary variables, each of which bears only one responsibility. The same temporary variable undertakes two different things, which will confuse code readers.

/**
 @startTime 2020-12-21 21:30
 @endTime 2020-12-21 23:50
 @startPage 131 
 @endPage 188
 @efficiency 188/6 = 31.3页/天
 @needDays 412/31.3 = 13天
 @overDay 2020-12-16 + 13天 =  2020-12-28
*/

7. Remove the assignment of the parameter

Replace the position of the parameter with a temporary variable.
First of all, I want to make sure that everyone is clear about the meaning of "assigning values ​​to parameters". If you pass an object named user as a parameter to a function, then "assigning a parameter" means changing user so that it refers to another object. If you do something on the "incoming object", that's okay, I always do it. I only discuss the situation that "user has been changed to point to another object".

8. Replace functions with function objects

You have a large function, where the use of local variables prevents you from using the extraction function. Put this function into a separate object, so that the local variable becomes a field in the object, and then you can in the same object Break this large function into multiple small functions.
"Motivation"
In this book, I continue to emphasize the beauty of small functions to readers. As long as relatively independent code is extracted from large functions, the readability of the code can be greatly improved.
"practice"

  1. Create a new class and name this class according to the purpose of the function to be processed.
  2. Create a final field in the new class to save the object where the original large function is located. We call this field the "source object". At the same time, for each temporary variable and each parameter of the original function, create a corresponding field in the new class to save it.
  3. Create a constructor in the new class and receive all the parameters of the source object and the original function as parameters.
  4. Create a compute function in the new class.
  5. Copy the code of the original function into the compute() function. If you need to call any function of the source object, please call it through the source object field.
  6. Compile.
  7. Replace the function body of the old function with the compute() function.

9. Replacement algorithm

Replace the function body with another algorithm.

Chapter 7 Moving Features Between Objects

1. Move function

In your program, there is a function that communicates more with another class outside of its class. Create a new function with similar behavior in the class that the function most frequently references. Turn the old function into a pure delegation relationship, or remove the old function completely.
"Transfer function" is the backbone of reconstruction theory. If a class has too many behaviors, or if a class has too much cooperation with another class to form a high degree of coupling, I will move the function. By this means, the classes in the system can be made simpler, and these classes will eventually achieve the tasks delivered by the system more cleanly.

2. Move fields

3. Refining

A certain class does what should be done by two classes, creates a new class, and moves related fields and functions from the old class to the new class.

4. Inline the class

A certain class does not do much, move all the characteristics of this class to another class, and then remove the class.

5. Hide commission relationship

When the client calls another object through a delegate class, all the functions required by the client are established on the service class to hide the delegate relationship.

public Person getManager(){
    
    
	return _department.getManager();
}

Only after completing the delegation relationship for all functions of the Department and modifying all the customers of Person accordingly, I can remove the access function getDepartment() in Person.

6. Remove the middleman

When a certain class does too many simple delegate actions, let the client directly call the delegated class.

7, the introduction of additional functions

Date start = new Date(previous.getYear(),previous.getMonth(),previous.getDate()+1);

Becomes

Date start = nextDay(previous);
private static Date nextDay(previous.getYear(),previous.getMonth(),previous.getDate()+1);

Seems to understand a little bit.
Adding functions is a stopgap measure after all. If possible, these functions should still be moved where they should be.

8. Introduce local extension

You need to provide some extra functions for the service class, but you cannot modify this class, create a new class, make it contain these extra functions, and make this extended class a subclass or wrapper class of the original class.
"Motivation"
When choosing between sub-categories and packaging categories, I usually prefer sub-categories because it requires less work. The biggest obstacle to making sub-categories is that if the original data is modifiable, one modification action cannot change the two copies. In this case, you must switch to the packaging category
"practice"

  1. Create an extended class as a subclass or wrapper class of the original class.
  2. Add the transformation constructor to the extension class. The so-called transformation constructor refers to the constructor that "accepts the original object as a parameter". If the subclassing scheme is adopted, then the transformation constructor should call the appropriate superclass constructor; if the packaging scheme is adopted, the transformation constructor should save the incoming parameters it gets in the form of instance variables for accepting delegates The original object.
  3. Add new features to the extended class.
  4. Change the original object to the extended object as needed.
  5. Move all the additional functions defined for the original class to the extended class.

Chapter 8 Reorganizing Data

1. Self-encapsulated fields

Create value/setting functions for the field, and only use these functions to access the field.

2. Replace data values ​​with objects

You have a data item that needs to be used with other data and behaviors to make sense to turn the data item into an object.

3. Change the value object to a reference object

4. Change the reference object to the value object

You have a reference object that is small, immutable, and difficult to manage. In this case, turn it into a value object.
It is sometimes not easy to choose between reference objects and value objects. After making a choice, you often need a way back.
If the reference object becomes difficult to use, perhaps it should be turned into a value object. The reference object must be controlled in some way, and you must always request the appropriate reference object from its controller. They can cause intricate associations between memory regions. In distributed and concurrent systems, immutable value objects are particularly useful because you don't need to consider their synchronization issues.

5. Replace arrays with objects

Replace the array with objects, and each element in the array is represented by a field.
The "motivation"
array is a common structure used to organize data. However, they should only be used to "accommodate a group of similar objects in a certain order." Sometimes you will find that an array contains many different objects, which can cause problems for users because it is difficult for them to remember conventions like "the first element of the array is the name of a person". Objects are different. You can use field names and function names to convey such information, without the need for comments. And using objects, you can also encapsulate information and add related behaviors to it using "moving functions".
I have done a data upload system before, with such a structure:

Map<String,String[]> hashMap = new HashMap<String,String[]>();
String[] data = new Data[4];
data[0] = "1";//状态state
data[1] = "1";//延展状态exstate
data[2] = "1";//数值
data[3] = "2020-12-21 23:22:00";//数据生成时间
String key = "01A01";//测点编号
hashMap.put(key,data);
...
for(String key : hashMap.keySet){
    
    
	//状态state、延展状态exstate、数值、数据生成时间
	String[] data = hashMap.get(key);
	String state = data[0];
	String exstate = data[1];
	String value = data[2];
	String time = data[3]'
}

Because there are basic data, real-time data, and minute cumulative data in the data, code projects with this structure are everywhere. The one written is a bad one. This upload program tortured me and I can't bear to look back.
"practice"

@Data
public class BasicData(){
    
    
	private int state;
	private int exstate;
	private double value;
	private Date time;
}

Map<String,BasicData> hashMap = new HashMap<String,BasicData>();
BasicData basicData = new BasicData();
basicData.setState = "1";
basicData.setExstate = "1";
basicData.setValue = 3.12;
String str = "2020-12-21 23:22:00";
basicData.setTime = DateUtil.StringToDate(str,"yyyy-MM-dd hh:mm:ss");
String key = "01A01";//测点编号
hashMap.put(key,basicData);
...
for(String key : hashMap.keySet){
    
    
	//状态state、延展状态exstate、数值、数据生成时间
	BasicData basicData = hashMap.get(key);
	String state = basicData.getState();
	String exstate = basicData.getExstate();
	double value = basicData.getValue();
	Date time = basicData.getTime();
}

Painful realization.
it's actually really easy.

/**
 @startTime 2020-12-22 21:30
 @endTime 2020-12-22 22:50
 @startPage 189 
 @endPage 235
 @efficiency 235/7 = 33.6页/天
 @needDays 412/33.6 = 12天
 @overDay 2020-12-16 + 12天 =  2020-12-27
*/

6. Copy the "monitored data"

You have some domain data in the GUI control, and domain functions need to access this data. Copy the data to a domain object. Establish an Observer mode to synchronize the repeated data in the domain object and the GUI object.
"Motivation"
A well-layered system should separate the code for processing the user interface and processing business logic. The reasons for this are as follows:

  1. You may need to use different user interfaces to express the same business logic. If you assume two responsibilities at the same time, the user interface will become too complicated;
  2. After being isolated from the GUI, the maintenance and evolution of domain objects will become easier, and you can even let different developers be responsible for different parts of the development.

7. Change one-way association to two-way association

Two classes need to use each other's characteristics, but there is only one one-way connection between them.
Add a back pointer and enable the modification function to update two connections at the same time.

8. Change two-way association to one-way association

Remove unnecessary associations.

9. Replace magic numbers with literal constants

You have a literal value with a special meaning. Create a constant, name it according to its meaning, and replace the above literal value with this constant.

10. Package fields

Encapsulate the field as private and provide the corresponding access function.

11. Package collection

12. Replace records with data types

Record-type structure is a common property of many programming environments. You may deal with some legacy programs, or you may need to communicate with the record structure through traditional APIs, or read records from data. At these times, you need to create an interface class to handle these foreign data. Move these data to Java beans.

13. Replace type codes with classes

14. Replace type codes with subclasses

Use polymorphism to handle changing behavior.

15. Replace the type code with state/strategy

You have a type code that affects the behavior of the class, but you cannot eliminate it through inheritance. At this point, you can replace the type code with a state object.

16. Replace subclasses with fields

The only difference between your subclasses is the "return constant data" function. Modify these functions so that they return a new field in the superclass, and then destroy the subclass.

Previous: "Refactoring to Improve the Design of Existing Code 1" Refactoring Principle
Next: [Writing high-quality code: 151 suggestions for improving Java programs]

Guess you like

Origin blog.csdn.net/guorui_java/article/details/111434891