Simplify function calls
1. Pull Up Field move Up
The two subclasses have the same field. Move this field to the superclass.
If the child classes are developed separately or combined during the refactoring process, you will often find that they have repeated features, especially for fields that are more likely to be repeated. Such fields sometimes have similar names, but they are not absolutely the same. The only way to determine whether several fields are repeated is to observe how the function uses them. If they are used in a similar way, You can generalize them to the superclass.
2. The Pull up Method function moves up
Some functions generate identical results in each subclass. Move the function to a superclass.
It is important to avoid repeated behaviors. Although the two repeated functions can work well, repeating itself will only become a breeding ground for errors, and there is no value in it. At any time, as long as there are duplicates in the system, you are at risk of "modifying one but failing to modify the other. It is usually difficult to find out duplicates.
If a function has the same body in each subclass, this is an obvious case for Pull Up Method (Method Up. Of course, the situation is not always so obvious. You can also feel free to refactor and see if the test program will complain, but this requires sufficient confidence in your test. Observing the differences between these potentially repeated functions is often rewarding: they often show behaviors that forget to test.
The Pull Up Method (Method move-Up) is often used immediately after other refactoring. Maybe you can find several functions in different subclasses, and they can be adjusted to the same function through some form of parameters. At this time, the simplest way is to adjust the parameters of these functions first, and then summarize them into the superclass. Of course, if you are confident enough, you can complete these two steps at a time.
In a special case, you also need to use the Pull Up Method (Method to move Up): The subclass function overwrites the superclass function, but still does the same work.
During the Pull Up Method process, the most troublesome point is that the promoted function may reference only the subclass rather than the super class. If a function is referenced, you can also promote it to the superclass, or create an abstract function in the superclass. In this process, you may need to modify the signature of a function or create a delegate function.
If the two functions are similar but different, you may first use Form Template Method to construct the same functions, and then upgrade them.
3. Pull up Constructor Body Constructor ontology move up
You have some constructors in each subclass, and their ontology is almost identical. Create a new constructor in the superclass and call it in the subclass constructor.
Constructors are amazing. They are not common functions, and they are more restrictive than normal functions.
If you see that the functions in each subclass share the same behavior, the first thought should be to extract the common behavior into an independent function and then promote the function to a superclass. For constructors, the common behavior of each other is often "Object Construction ". At this time, you need to provide a constructor in the superclass, and then let the subclass call it. In many cases, the only action of a subclass constructor is to call a superclass. It cannot be used here
Pull Up Method (Method Up), because you cannot inherit the superclass constructor In the subclass.
If the refactoring process is too complex, you can consider using Replace Constructor with Factory Method (Replace constructors with Factory functions ).
4. Push down Method function move down
A function in a superclass is only related to some subclasses. Move this function to the related child classes.
The push down Method and Pull Up Method are the opposite. When it is necessary to move some actions from the superclass to a specific subclass, use the push down Method (function down), which is usually used only in this case. You may need it after using Extract Subclass (Extract Subclass.
5. Push down the Fiedld field to move down
A field in a superclass is only used by some subclasses. This field is moved to the subclasses that require it.
If only some subclasses need a field in the superclass, you can use this item for reconstruction.
6. Extract Subclass refining Subclass
Some features in the class are only used by some instances. Create a new subclass and move the features mentioned above to the subclass.
The main motivation for using extract subclass is: You find that some behaviors in the class are only used by some instances, and other instances do not need them. Sometimes the difference in this behavior is identified by type codes. In this case, you can use replace type code with subclass (replace type code with subclass) or replace type code with State/Strategy (replace type code with State policy ). However, it is not necessary to have a type code to indicate that subclass needs to be considered.
Extract class is another choice beyond extract subclass. The choice between two is actually the choice between delegation and inheritance. Extract subclass (extract subclass) is usually easier, but it also has restrictions: once an object is created, you cannot change the type-related behavior, but if you use Extract
Class, you only need to insert another component to change the behavior of the object. In addition, subclass can only represent a group of changes. If you want a class to change in several different ways, you must use the delegate.
7. Extract superclass refining superclass
The two classes have similar features. Create a superclass for these two classes and move the same features to the superclass.
Repeated Code is one of the worst in the system. If you do the same thing in different places, once you need to modify those actions, you have to make more changes in plain white.
Some form of repeated code is: two classes do similar things in the same way, Or do similar things in different ways. Objects provide a mechanism to simplify this situation, that is, inheritance. However, before creating these generic classes, you often cannot find such a common class. Therefore, after the common classes appear, you often start to establish the inheritance structure.
Another option is extract class (extraction class ). The choice between the two schemes is actually the choice between inheritance and delegation. If two classes can share behaviors or interfaces, inheritance is simple. If you choose the wrong one, there will always be replace inheritance with delegation (replace inheritance with Commission) this bottle of regret medicine can be taken.
8. Extract interface extraction Interface
Several customers use the same subset of the class interface, or the interfaces of the two classes are the same. Extracts the same subset into an independent interface.
There are several methods for mutual use between classes. "Using a class" usually means that all the responsibility zones of the class are used. In another case, a group of customers only use a specific subset of the class responsibility area. In another case, this class needs to work with all classes that assist in processing certain requests.
In the latter two cases, it is usually meaningful to separate the actually used part of the responsibility, because this can make the system usage clearer and make it easier to see the responsibility division of the system. If the new class needs to support the previous subset, you can also see something in the subset.
In many object-oriented languages, this division of responsibility is achieved through multi-inheritance. In C #, you can use interfaces to demonstrate and implement the preceding requirements.
There are some similarities between extract subclass and extract interface. Extract interface (extract Interface) can only extract common interfaces, but cannot extract common code. The use of extract interface (extract Interface) may cause an unpleasant "DUPLICATE" bad taste. Fortunately, you can use Extract
Class (extract Class) first puts the common behavior into a component, and then delegates the work to the component to solve this problem. If there are many common behaviors, Extract Superclass (Extract super class) is relatively simple, but each class can only have one super class.
If a class plays different roles in different environments, it is a good idea to use interfaces. You can Extract the corresponding interfaces for each role using the Extract Interface. Another scenario where Extract Interface (Extract Interface) can be used is: You want to describe the external dependent Interface of a class. If you want to add other types of service objects in the future. You only need to require them to implement this interface.
9. Collapse Hierarchy fold Inheritance System
There is no big difference between a superclass and a subclass. Integrate them into one.
If you have written an inheritance system, you will know that the inheritance system is easily overly complicated. The so-called reconstruction of the inheritance system usually involves moving functions and fields up and down in the system. After completing these actions, you may find that a subclass does not bring this value. Therefore, you need to combine the superclass and subclasses.
10. Create a TemPlate function From TemPlate Method
You have some sub-classes, some of which execute similar operations in the same order, but the details of each operation are different. Put these operations into independent functions, and keep them all with the same signature, so the original functions become the same, and then move the original functions to the superclass.
Inheritance is a powerful tool to avoid repeated behaviors. Whenever you see similar functions in the two subclasses, You can promote them to the superclass. But what if these functions are not exactly the same? It is still necessary to avoid repetition as much as possible, but the substantial difference between these functions must be maintained.
A common case is that the two functions perform roughly similar operations in the same order, but the operations are different. In this case, we can move the execution sequence to the superclass, and use polymorphism to ensure that each operation remains different. Such a function is called Template Method ).
11. Replace Inheritance with delegation
A subclass only uses a portion of the superclass interface or data that does not need to be inherited. Create a new field in the subclass to save the superclass. Adjust the subclass function to delegate the superclass, and then remove the inheritance relationship between the two.
Inheritance is a good thing, but sometimes it is not what you want. You often encounter this situation: you inherited a class from the beginning, and then found that many operations in the super class are not really applicable to the subclass. In this case, your interfaces do not actually reflect the sub-class functions. Alternatively, you may find that you inherit a lot of data that is not required by the subclass from the superclass, or you may find that some protected functions in the superclass do not have any significance for the subclass.
You can choose tolerance and accept the traditional saying that subclass can only use part of the superclass function. But the result is that the message transmitted by the Code is the same as your intention. You should remove it.
If you replace inheritance with delegation, you can clearly show that you only need a part of the delegate function. Which part of the interface should be used and which part should be ignored, which is under your control. The cost of doing so is to write additional delegate functions, but these functions are simple and rarely error.
12. Replace delegation with Inheritance to Replace delegation with Inheritance
You use the delegate relationship between two classes, and often write many very simple delegate functions for the entire interface. Let the delegate class inherit the delegate class.
This refactoring is the opposite of replace inheritance with delegation (replacing inheritance with delegation. If you find that you need to delegate all functions in the class and spend a lot of effort writing all extremely simple delegate functions, this Refactoring can help you easily go back and use inheritance.
Note: if you do not use all functions of the delegate class, replace delegation with inheritance (replace delegation with inheritance) should not be used ), because subclass should always follow the superclass interface. If too many delegate functions are bothering you, you have another option: You can remove middle man (remove man-in-the-middle) to allow the client to call the delegate function on its own, or you can use Extract
Superclass (extract Superclass) extracts the same parts of the two class interfaces into the Superclass, and then let the two classes inherit the new Superclass; you can also use Extract Superclass (Extract Superclass) in a similar way ).
Another situation that requires caution is that the trustee object is shared by more than one other object, and the trustee object is variable. In this case, you cannot replace the delegate relationship with the inheritance relationship, because the data can no longer be shared. Data sharing is a responsibility that must be borne by the trustee. You cannot transfer it to the inheritance relationship. If the trusted object is immutable, data sharing is not a problem, because you can copy the object with confidence.