You get a bonus - 1 coin for daily activity.
Now you have 1 coin
Refactoring techniques. Moving methods between classes
Lecture
If you have placed the functionality of the classes is not the best way - this is not a reason to despair.
Refactoring this group shows how to safely move functionality from one class to another, create new classes, and also hide implementation details from public access.
Moving method
Problem: The method is used in another class more than in its own.
Solution: Create a new method in the class that uses it more than others, and transfer the code from the old method there. Turn the original method code into a call to a new method in another class or remove it altogether.
Moving field
Problem: The field is used in another class more than in its own.
Solution: Create a field in the new class and redirect all users of the old field to it.
Class extraction
Problem: One class works for two.
Solution: Create a new class, move to it the fields and methods that are responsible for certain functionality.
Class embedding
Problem: The class does almost nothing, is not responsible for anything, and no responsibility is planned for this class.
Solution: Move all features from the described class to another.
Delegation Concealment
Problem: The client receives object B from the field or method of object A. Then the client calls some method of object B.
Solution: Create a new method in class A, which would delegate the call to object B. Thus, the client will no longer know about class B and depend on it.
Removing a reseller
Problem: The class has too many methods that simply delegate work to other objects.
Solution: Remove these methods and force the client to call the final methods directly.
Introduction of the external method
Problem: The utility class does not contain the method you need, and you cannot add a method to this class.
Solution: Add a method to the client class and pass in it a utility class object as an argument.
Introduction of local extension
Problem: The utility class lacks some methods that you need. You cannot add them to this class.
Solution: Create a new class that would contain these methods, and make it a successor of the service class, or its wrapper.
same known as: Move Method
Refactoring Moving Method
Problem
The method is used in another class more than in its own.
Decision
Create a new method in the class that uses it more than others, and transfer the code from the old method there. Turn the original method code into a call to a new method in another class or remove it altogether.
Reasons for refactoring
You want to move a method to a class that contains data with which this method basically works. This increases connectivity within classes .
You want to move a method to remove or reduce the dependence of the class that calls this method on the class in which it was located. This can be useful if the calling class already has a dependency on the class where you plan to transfer the method. Thus, you reduce connectivity between classes .
Refactoring order
Check out all the features used by the old method in its class. Perhaps they should also be moved. Follow this rule - if the feature is used only by the method you are interested in, it should be transferred accurately. If the feature is used by other methods, it may be necessary to transfer these methods. Sometimes it is much easier to move a pack of methods than to configure the interaction between them in different classes.
Check if the method is defined in the superclasses and subclasses of the receiver. If so, you will either have to abandon the idea of transfer, or implement a kind of polymorphism in the recipient class to provide different functionality of the method, which was divided into donor classes.
Declare a new method in a class receiver. Perhaps you should come up with a new name for the method, which in the new class will suit it more.
Determine how you will contact the class of the recipient. It is quite possible that you already have a field or method that returns a suitable object, but if not, you will need to write a new method or field in which the object of the class of the receiver would be stored.
Now you have a way to access the receiver object and a new method in its class. With this all you can already turn the old method into a call to the new method.
Rate, is it possible to remove the old method at all? In this case, it will be necessary in all the places where this method is used, to put an appeal to the new.
Also known as: Move Field
Refactoring Moving Fields
Problem
The field is used in another class more than in its own.
Decision
Create a field in the new class and redirect all users of the old field to it.
Reasons for refactoring
Often, fields are carried as part of extracting one class from another. It is not easy to decide which class should remain in the field. Nevertheless, we have a good recipe - the field should be where the methods are located that use it (or where there are more of these methods).
This rule will help you in other cases where the field is simply not where it is needed.
Refactoring order
If the field is public, it will be much easier for you to refactor if you make it private and provide public access methods (you can use refactoring to encapsulate the field).
Create the same field with access methods in the target class.
Determine how you will contact the class of the recipient. It is possible that you already have a field or method that returns a suitable object. If not, you will need to write a new method or field in which the object of the class of the recipient would be stored.
Replace all references to the old field with the corresponding method calls in the class of the receiver. If the field is not private, do it in the superclass and in the subclasses.
Delete the field in the source class.
Related refactorings
Moving field
Helps refactoring
Class extraction
Class embedding
Fights odor
Shot Shot
Parallel inheritance hierarchies
Inappropriate intimacy
Also known as: Extract Class
Refactoring Class Extraction
Problem
One class works for two.
Decision
Create a new class, move to it the fields and methods that are responsible for a certain functionality.
Reasons for refactoring
Classes always look sharp and clear from the start. They do their job and do not climb into the duties of other classes. However, over the course of the life of the program, one method is added — here, one field — there. As a result, some classes get a ton of extra responsibilities.
Merits
This refactoring is intended to assist in adhering to the principle of the sole duty of the class . This makes the code for your classes clearer and clearer.
Classes with the only responsibility are more reliable and resistant to change. For example, you have a class responsible for ten different things. And when you have to make changes to it, you risk breaking other things when adjusting one thing.
disadvantages
If you overdo it during this refactoring, you will have to resort to embedding the class.
Refactoring order
Before starting refactoring, be sure to determine exactly how the class should be divided.
Create a new class that will contain the selected functionality.
Create a connection between the old and the new class. Best of all, if this connection is one-way; while the second class can be reused without problems. On the other hand, if you think that this is necessary, you can always create two-way communication.
Use the moving field and moving method for each field and method that you choose to move to the new class. For methods, it makes sense to start from private, so you reduce the likelihood of making a lot of mistakes. Try to move a little and test the result after each move, it will save you from having to correct a large number of errors at the very end.
Once done with the move, look again at the resulting classes. Perhaps the old class now makes sense to call it differently because of its changed responsibilities. Check again whether it is possible to get rid of two-way communication between classes, if it has arisen.
Another nuance is the availability of a new class from the outside. You can completely hide it from the client, making it private, while managing its fields from the old class. Or make it public by giving the customer the opportunity to directly change values. The decision depends on how safe for the behavior of the old class will be unexpected direct changes of values in the new class.
Anti-refactoring
Class embedding
Related refactorings
Extract subclass
Replacing a simple field with an object
Fights odor
Code duplication
Big class
Divergent modifications
Data groups
Obsession with elementary types
Temporary field
Inappropriate intimacy
Also Known As: Inline Class
Refactoring Class Embedding
Problem
The class does almost nothing, is not responsible for anything, and no responsibility is planned for this class.
Decision
Move all features from the described class to another.
Reasons for refactoring
Often, this refactoring is the result of the recent "relocation" of part of the class features to others, after which little remains of the original class.
Merits
Less useless classes - more free RAM, including in your head.
Refactoring order
Create in the class-receiver public fields and methods that are in the class-donor. Methods should refer to similar methods of the donor class.
Replace all references to the donor class with references to the fields and methods of the receiver class.
It's time to test the program and make sure that no errors were made during the work. If the tests show that everything works as it should, we begin to use the method transfer and the field transfer in order to completely move all the functionality to the target class from the original class. We continue to do this until the original class is completely empty.
Remove the original class.
Anti-refactoring
Class extraction
Fights odor
Shot Shot
Lazy class
Theoretical community
Also known as: Hide Delegate
Refactoring Delegation Hiding
Problem
The client receives object B from the field or method of object A. The client then calls some method of object B.
Decision
Create a new method in class A, which would delegate the call to object B. Thus, the client will no longer know about class B and depend on it.
Reasons for refactoring
First you need to decide on the names:
A server is an object that the client has direct access to.
A delegate is the final object that contains the functionality that the client needs.
A call chain appears when a client requests one object from another, then the second object requests another, and so on. Such call sequences mean that the client is connected with navigating through the class structure. Any changes to intermediate links imply the need to modify the client.
Merits
Hides delegation from the client. The less client code knows the details about the relationships between objects, the easier it will be later to make changes to the program.
disadvantages
If it is necessary to create too many delegating methods, the class-server risks becoming an unnecessary intermediate and leading to a pack of middleman.
Refactoring order
For each delegate class method called by the client, you need to create a method in the server class that delegates the call to the delegate class .
Modify the client code so that it calls the server class methods.
If, after all changes, the client no longer needs the delegate class , you can remove the delegateclass access method from the server class (the method that was used initially to get the delegate class ).
Anti-refactoring
Deleting a reseller
Fights odor
Call chain
Inappropriate intimacy
Also known as: Move Field
Refactoring Moving Fields
Problem
The field is used in another class more than in its own.
Decision
Create a field in the new class and redirect all users of the old field to it.
Reasons for refactoring
Often, fields are carried as part of extracting one class from another. It is not easy to decide which class should remain in the field. Nevertheless, we have a good recipe - the field should be where the methods are located that use it (or where there are more of these methods).
This rule will help you in other cases where the field is simply not where it is needed.
Refactoring order
If the field is public, it will be much easier for you to refactor if you make it private and provide public access methods (you can use refactoring to encapsulate the field).
Create the same field with access methods in the target class.
Determine how you will contact the class of the recipient. It is possible that you already have a field or method that returns a suitable object. If not, you will need to write a new method or field in which the object of the class of the recipient would be stored.
Replace all references to the old field with the corresponding method calls in the class of the receiver. If the field is not private, do it in the superclass and in the subclasses.
Delete the field in the source class.
Related refactorings
Moving field
Helps refactoring
Class extraction
Class embedding
Fights odor
Shot Shot
Parallel inheritance hierarchies
Inappropriate intimacy
Also known as: Remove Middle Man
Refactoring Removing a mediator
Problem
The class has too many methods that simply delegate work to other objects.
Decision
Remove these methods and force the client to call the final methods directly.
Reasons for refactoring
In this refactoring we will use the names from the concealment of the delegation, namely:
A server is an object that the client has direct access to.
A delegate is the final object that contains the functionality that the client needs.
There are two kinds of problems:
The class server does nothing on its own, creating useless complexity. In this case, it is worth considering whether this class is needed at all.
Every time a new feature appears in the delegate , you need to create a delegating method for it in the server class . This is expensive with a large number of changes.
Refactoring order
Create a getter to access the delegateclass object from the server class object.
Replace calls to the delegating methods of the server class with direct calls to the methods of the delegate class .
Anti-refactoring
Delegation Concealment
Fights odor
Mediator
Also known as: Introduce Foreign Method
Refactoring Introducing External Method
Problem
The utility class does not contain the method you need, and you cannot add a method to this class.
Decision
Add a method to the client class and pass an object of the utility class to it as an argument.
class Report {
// ...
void sendReport () {
Date nextDay = new Date (previousEnd.getYear (),
previousEnd.getMonth (), previousEnd.getDate () + 1);
// ...
}
}
class Report {
// ...
void sendReport () {
Date newStart = nextDay (previousEnd);
// ...
}
private static Date nextDay (Date arg) {
return new Date (arg.getYear (), arg.getMonth (), arg.getDate () + 1);
}
}
class Report {
// ...
sendReport (): void {
let nextDay: Date = new Date (previousEnd.getYear (),
previousEnd.getMonth (), previousEnd.getDate () + 1);
// ...
}
}
class Report {
// ...
sendReport () {
let newStart: Date = nextDay (previousEnd);
// ...
}
private static nextDay (arg: Date): Date {
return new Date (arg.getFullYear (), arg.getMonth (), arg.getDate () + 1);
}
}
Reasons for refactoring
You have code that uses data and methods of a particular class. You come to the conclusion that this code will look and work much better inside the new method in this class. However, you have no opportunity to add such a method to a class (for example, because the class is in a third-party library).
This refactoring is especially beneficial in cases where a section of code that you want to transfer to a method is repeated several times in different places in the program.
Since you pass a utility class object to the parameters of a new method, you have access to all of its fields. Inside this method, you can do almost everything you need, as if the method were part of a service class.
Merits
Removes duplicate code. If your code section is repeated in several places, you can replace them with a method call. This is more convenient than duplication, even taking into account the fact that the external method is not where we would like.
disadvantages
Причины того, почему метод служебного класса находится в клиентском классе, не всегда очевидны для того специалиста, который будет поддерживать код после вас. Если данный метод может быть использован и в других классах, имеет смысл создать обёртку над служебным классом, и поместить метод туда. То же самое имеет смысл сделать, если таких служебных методов несколько. В этом поможет рефакторинг введение локального расширения.
Refactoring order
Создайте новый метод в клиентском классе.
В этом методе создайте параметр, в который будет передаваться объект служебного класса. Если этот объект может быть получен из клиентского класса, параметр можно не создавать.
Извлеките волнующие вас участки кода в этот метод и замените их вызовами метода.
Обязательно оставьте в комментарии к этому методу метку Foreign method и призыв поместить этот метод в служебный класс, если такая возможность появится в дальнейшем. Это облегчит понимание того, почему этот метод находится в данном классе для тех, кто будет поддерживать программный продукт в будущем.
Родственные рефакторинги
Введение локального расширения
Вынести все расширенные методы в отдельный класс обёртку/наследник служебного класса.
Борется с запахом
Неполнота библиотечного класса
Также известен как: Introduce Local Extension
Рефакторинг Введение локального расширения
Problem
В служебном классе отсутствуют некоторые методы, которые вам нужны. При этом добавить их в этот класс вы не можете.
Decision
Create a new class that would contain these methods, and make it a successor of the service class, or its wrapper.
Reasons for refactoring
There is no method you need in the class you are using. Or even worse, you cannot add them there (for example, because the classes are in a third-party library). You have two options:
Create a subclass of the class of interest, which will contain new methods, and inherit everything else from the parent class. This path is easier, but sometimes it is blocked in the utility class itself with the help of the final directive.
Create a wrapper class that will contain all the new methods, and delegate the rest to the associated object of the service class. This path is more laborious, since you will need to have in the appendage not only the code for maintaining communication between the wrapper and the service object, but also a large number of simple delegating methods that will emulate the public interface of the service class.
Merits
By placing additional methods in a separate extension class (wrapper or subclass), you do not clutter client classes with code that does not belong to them. This increases the connectivity of the program components and the possibility of their reuse.
Refactoring order
Create a new extension class:
or make it a successor to the service class;
or, if you decide to make a wrapper, create a field in it to store the object of the utility class to which delegation will occur. In this case, you will need to create methods that repeat the public methods of the service class and contain a simple delegation to the methods of the service object.
Create a constructor that uses the parameters of the utility class constructor.
In addition, create an alternative "converting" constructor that accepts only the object of the original class in the parameters. This will help in substituting the extension instead of the objects of the original class.
Create new advanced methods in the class. Move external methods from other classes into it, or delete them if the extension already has such functionality.
Replace the use of the utility class with a new extension class in those places where you need extended functionality.
Comments
To leave a comment
If you have any suggestion, idea, thanks or comment,
feel free to write. We really value feedback and are glad to hear your opinion.
Comments
To leave a comment
Refactoring theory
Terms: Refactoring theory