Refactoring-improved the design of existing code: eight methods for moving between objects (5)

Source: Internet
Author: User

In the process of object-oriented programming, clarify the responsibilities of this object. Class should be: do what you should do, do what you should do,

1. Move Method Move Function

Class behavior to achieve a single responsibility do not go beyond the Proxy: In your program, there is a function to communicate with another class outside of the resident class: Call the latter, or be called by the latter. Create a new function with similar behavior in the class most commonly referenced by this function. Program the old function as a pure delegate function, or completely remove the old function.


The "moving function" is the pillar of refactoring theory. If a class has too many behaviors, or if a class is highly coupled with another class, you need to move the function. Through this method, classes in the system can be simpler, and these classes will eventually implement system delivery more cleanly.
Browse all functions of the class and find out the function: the number of times that another object is used is more than the number of times that the object is resident. This check should be performed once some fields are moved. Once a function that may be moved is found, observe the end that calls it and the end that it calls. It has inherited any of its redefinition functions in the system. Then, the moving path is determined based on "The function communicates more with which object.
This is often not an easy decision. If you are not sure whether to move a function, continue to observe other functions. Moving other functions makes this decision easier. Sometimes, even if you move other functions, it is difficult to make a decision on the current function. In fact, this is no big deal. If it is really difficult to make a decision, maybe "moving this function or not" is not that important. Therefore, it can be changed by instinct.

2. Move Field

The attributes of a class should be changed: In your program, a field is used more by another class outside of its resident class. Create a new field in the target class, modify all users of the Source Field, and change them to a new field.

Moving states and behaviors between classes is an essential measure in the refactoring process. As the system develops, you will find that you need a new class and need to drag the existing work responsibilities to the new class. This week's seemingly reasonable and correct design decisions may not be correct by the next week. This is no problem. If you have never encountered such a situation, it will be a problem.

If you find that more functions are used for a field in another class other than its resident class, you should consider moving this field. The above-mentioned "use" may be carried out indirectly by setting the value/value function. It is also possible to move the user (a function) of this field, depending on whether the interface needs to be kept unchanged. If these functions seem to be suitable for staying in the same place, choose to move the field.

When using extract class (extract class), you may also need to move fields. In this case, you can first move the field and then move the function.

3. Extract class extraction class

A class should be a clear abstraction, deal with some clear responsibilities, and break down a class into a small class: A class has done something that should be done by two classes. Create a new class to move related fields and functions from the old class to the new class.

A class should be a clear abstraction to deal with some clear responsibilities. However, in actual work, classes will continue to grow and expand. You will add some features here and where to add some data. When you add a new responsibility to a class, you will feel that it is not worthwhile to separate a separate class from this responsibility. As the number of responsibilities increases, this class becomes too complex.
Soon, your class will become messy.
Such classes often contain a large amount of functions and data. Such classes are too big to understand. In this case, you need to consider which parts can be separated and separate them into a separate class. If some data and some functions always appear together, and some data often changes at the same time or even depend on each other, this means you should separate them. A useful test is to ask yourself, if some fields and functions are removed, what will happen? Other fields and functions become meaningless. Another subclass method that is often used when the signal appears in the development stage. If you find that subclass only affects some of the features of the class, or if you find that some features need to be subclass in one way, some features need to be subclass in another way, this means that you need to break down the original class.


4. Inline Class: concatenate classes

Small classes move directly to the main category: A class does not do much. Move all features of this class to another class, and then remove the original class.

Inline Class is the opposite of Extract Class. If a class no longer bears sufficient responsibilities and has no reason to exist independently (this is usually because the previous refactoring action removes the responsibility of this class ), select the most frequent user (also a class) of this "shrinking class" and use Inline
The Class method is to insert the "shrink Class" into another Class.

5. Hide the Delegate relationship with Hide Delegate

The customer calls another object through one delegate class. Create all functions required by the customer in the service class to hide the delegate relationship.


Encapsulation is one of the key features, even if it is not a key feature of an object. "Encapsulation" means that every object should have as little knowledge as possible about other parts of the system. In this way, once a change occurs, there will be fewer objects to understand the change, which will make the change easier.

If a customer first obtains another object through the service object field and then calls the latter's function, the customer must know this level of delegation relationship. In case of a change in the delegated relationship, the customer must also change accordingly. You can place a simple delegate function on the service object to hide the delegate relationship and remove this dependency. In this way, even if the delegated relationship changes in the future, the changes will be restricted to the service object and will not affect the customer.

For some or all customers, you may find that it is necessary to use Extract Class first ). Once you have hidden the delegate relationship from all customers, you no longer need to publish the delegated object in the service object interface.

6. Remove middle Man Remove Man in the middle

A class performs too many simple delegation actions.Let the customer directly call the delegate class.

In the "motivation" of Hide Delegate (hiding delegation relations), we talked about the benefits of "encapsulating Delegate objects. However, this encapsulation also has to pay the price. The price is that whenever the customer wants to use the new feature of the delegate class, you must add a simple delegate function to the server. With more and more features (functions) of the delegate class, this process makes you suffer. The service class has completely changed to a "man-in-the-middle", so you should let the customer directly call the trustee class.

It is hard to say to what extent it is suitable to hide data. Fortunately, with Hide Delegate (hiding the Delegate relationship) and Remove Middle Man (removing the Man in the Middle), you don't have to worry about this. Because you can make constant adjustments during system operation. As the system changes, the "appropriate degree of hiding" Scale also changes accordingly. 6 months ago, the appropriate package may seem clumsy today. Refactoring means you never have to say sorry-you just need to fix the problem.


7. Introduce Foreign Method introduces an additional function

You need to add a function to the class that provides services, but you cannot modify this class. Create a function in the customer class and input a service instance as the first parameter.


This happens too many times. You are using a class. It is really good and provides you with all the services you need. Then you need a new service, but this class cannot be supplied. So you began to curse "Why can't you do this ?" If you can modify the source code, you can add a new function. If you cannot, you have to encode the function on the client to supplement the function you want.

If the customer class only uses this function once, the extra coding work is no big deal, and may not even need the class that originally provided the service. However, if you need to use this function multiple times, you have to repeat the code. Repeated code is the source of all evil software. These repeated codes should be extracted and put into a function. During this refactoring, if you add a function to implement a function, it is a clear signal that this function should be implemented in the class that provides services.

If you find that you have created a large number of additional functions for a service class, or you find that many classes require the same additional functions, you should not use this item for reconstruction, instead, use introduce local extension (introducing local extensions ).

But don't forget: the addition of functions is always a matter of expediency. If possible, you should still move these functions to their ideal home. If you cannot perform this operation because of code ownership, you can hand over the added function to the service provider and ask him to implement this function in the service class.


8. Introduce local extension introduces local extensions you need to provide some additional functions for the service class, but you cannot modify this class. Create a new class to include these additional functions. Make this extension a subclass or package of the source class.

Class authors cannot predict the future. They often fail to prepare some useful functions for you. If you may modify the source code, the final solution is to directly add the functions you need. But you often cannot modify the source code. If you only need one or two functions, you can use Introduce Foreign Method (to Introduce the external function ). However, if you need more than two additional functions, it is difficult to control them. So you need to organize these functions together and put them in a proper place. To achieve this, two standard object technologies-subclassing and wrapping are obvious methods. In this case, subclass and packaging classes are collectively referred to as local extensions.

Local extension is an independent class, but it is also the word type of the extended class: it provides all the features of the source class and adds new features. You can use local extensions to replace any source class.

Using local Extensions allows you to adhere to the principle that functions and data should be uniformly encapsulated. If you keep placing code that is supposed to be included in the extension class in other classes, it will only make other classes overly complicated and make other functions difficult to reuse.

Subclass is preferred when selecting between subclass and packaging class. This is because the workload is relatively small. The biggest obstacle to subclass creation is that it must be implemented during object creation. If you can take over the object creation process, of course it is okay. But if you want to use the local extension after the object is created, the problem arises. In this case, the subclass scheme must also generate a subclass object. In this case, if other objects reference the old object, we will have two objects to save the original data at the same time. If the original data cannot be modified, it is okay. You can copy the data with peace of mind. However, if the original data can be modified, the problem arises because one modification action cannot change two copies at the same time. In this case, you must switch to the packaging class. When a packaging class is used, modifications to the local extension will affect the original object, and vice versa.

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.