CSC/ECE 517 Fall 2009/wiki1a 7 sm: Difference between revisions
Suryaramana (talk | contribs) No edit summary |
No edit summary |
||
(30 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
== '''Categorization of refactoring''' == | == '''Categorization of refactoring''' == | ||
=== Problem Statement === | |||
The list of refactoring has become quite long. But people don't remember long lists very well. To promote learning the different patterns, they should be categorized in some way, or perhaps, along various dimensions. Take the list of refactoring available at refactoring.org (and/or elsewhere) and categorize them along as many different dimensions as makes sense. Write up a description of the refactoring landscape. | The list of refactoring has become quite long. But people don't remember long lists very well. To promote learning the different patterns, they should be categorized in some way, or perhaps, along various dimensions. Take the list of refactoring available at refactoring.org (and/or elsewhere) and categorize them along as many different dimensions as makes sense. Write up a description of the refactoring landscape. | ||
Line 13: | Line 14: | ||
== '''Categorizing Refactoring Techniques According to Broad Goals ''' == | |||
Refactoring techniques can be classified according to the broad goals they intend to achieve. The different categories are as follows. | |||
=== '''Composing Methods''' === | |||
The refactoring methods coming under this basically deal with composing new methods to package the code properly. Most come from the method, class etc being too long and not representing its true functionality or trying to do a lot of things at once. So modularization is the key goal here. | |||
'''''Example''''' | |||
''' Before''' | |||
void printDetails(Employee e) | |||
{ | |||
System.out.println(e.id); | |||
System.out.println(e.name); | |||
Address addr = e.getAddress(); | |||
System.out.println(addr.street); | |||
System.out.println(addr.city); | |||
System.out.println(addr.zip); | |||
System.out.println(addr.state); | |||
} | |||
'''After''' | |||
void printDetails(Employee e) | |||
{ | |||
System.out.println(e.id); | |||
System.out.println(e.name); | |||
printAddress(e.getAddress()); | |||
} | |||
void printAddress(Address addr) | |||
{ | |||
System.out.println(addr.street); | |||
System.out.println(addr.city); | |||
System.out.println(addr.zip); | |||
System.out.println(addr.state); | |||
} | |||
'''''Extract Method''''' | |||
Code fragment which can be grouped together so create a new method whose name explains the purpose of the method.Used when a method is too long or when it starts needing comments to reveal its purpose (and so is not self explanatory). For additional information regarding this topic click [http://www.refactoring.com/catalog/extractMethod.html here] | |||
'''''Inline Method''''' | |||
Used when a method’s body is as clear as the name of the method. Executed by putting the method's body into the body of its callers and remove the method.Sometimes the method body is so concise and clear that we would want to define the method in place and get rid of the method. For additional information regarding this topic click [http://www.refactoring.com/catalog/inlineMethod.html here] | |||
'''''Introduce Explaining Variable''''' | |||
If there is a complicated expression, put the result into a temporary variable with a meaninigful name.To make the expression and thus the code easier to understand. For additional information regarding this topic click [http://www.refactoring.com/catalog/introduceExplainingVariable.html here] | |||
'''''Replace Temp With Query''''' | |||
Instead of using a temporary variable to hold the result of an experession replace them with a method(query) and replace the expressions with the query method. This refactoring method is used as a preparation of the normal Extract Method refactoring method mainly because the existence of several temporary variables tend to make the ‘extracted’ method quite long since we have to pass them along to the extracted method. (But if the variable is assigned to more than once then consider the next method Split Temp Variable). For additional information regarding this topic click [http://www.refactoring.com/catalog/replaceTempWithQuery.html here] | |||
'''''Split Temporary Variable''''' | |||
If we have a temporary variable assigned to more than once, but is not a loop variable nor a collecting temporary variable. Make a separate temporary variable for each assignment.Some temporary variable (like ‘i’ in for loops) are just plalceholders for each iteration. On the other hand some temp variables are used to hold values of long expressions. Now if that variable is assigned again, it means that the variable more than one responsibility which is discouraged for a temporary variable. Any variable with more than one responsibility should be replaced with a temp for each responsibility. Using a temp for two different things is very confusing for the reader. For additional information regarding this topic click [http://www.refactoring.com/catalog/splitTemporaryVariable.html here] | |||
'''''Remove Assignment To Parameter''''' | |||
If the code assigns to a passed in parameter, use temp variable instead.In Java assigning to a parameter which is a primitive object (int, char etc, not objects) is fine because they are passed by reference. When objects are passed, the reference to the object is passed by value(not the copy of object, but copy of reference to original object). Hence if the reference is reassigned (e.g. swapping) that makes no change to original object but if the passed reference is used to reassign the member variables of the passed object, that may pose problems. Moreover any language which uses pass by reference will have problems if passed parameters are reassigned. For additional information regarding this topic click [http://www.refactoring.com/catalog/removeAssignmentsToParameters.html here] | |||
'''''Replace Method With Method Object''''' | |||
As we saw earlier, having a long list of local variable hinders the use of Extract Method. We overcame this earlier by Extract Temp with Query but sometimes breaking a method is not possible. So instead of breaking the method, we create an object out of the method so the local variables become fields which are now easily accessible. For additional information regarding this topic click [http://www.refactoring.com/catalog/replaceMethodWithMethodObject.html here] | |||
'''''Substitute Algorithm''''' | |||
It is one of the simplest to execute in which an algorithm in a method is replaced with another set of more coherent and lucid algorithm just because we found a an easier algorithm for a set of code. For additional information regarding this topic click [http://www.refactoring.com/catalog/substituteAlgorithm.html here] | |||
=== '''Moving features between objects''' === | |||
Object oriented programming is all about objects and their attributes and responsibilities. But creating object structure and deciding where to put the responsibility is tricky. So once created, need may arise due to more insight or due to testing of the classes that these attributes may need to be changed. These refactorings come under this category. | |||
'''''Example''''' | |||
''' Before''' | |||
Class Employee | |||
{ | |||
String name; | |||
int officeAreaCode; | |||
int officeNumber; | |||
int residenceAreaCode; | |||
int residenceNumber; | |||
} | |||
'''After''' | |||
Class Employee | |||
{ | |||
String name; | |||
TelephoneNumber residencePhone; | |||
TelephoneNumber officePhone; | |||
} | |||
Class TelephoneNumber | |||
{ | |||
int areaCode; | |||
int phoneNumber; | |||
} | |||
'''''Extract Class''''' | |||
We have a class which has more responsibility than it should have (which may include both attributes and methods). So we can create a new class by taking out some features which can be separated from the existing class.Large sized classes are not easy to comprehend and lead us away from the concept of abstraction. For additional information regarding this topic click [http://www.refactoring.com/catalog/extractClass.html here] | |||
'''''Hide Delegate (Opposite Of Remove Middle Man)''''' | |||
The client should know and thus be very less dependent on the server code for execution. If a client calls a method defined on a field of the server directly then any changes which have to be made on this delegate has to be propogated to the client which is not desirable. So a delegating method can be added on server which limits the change to the client whenever a change is made to the server. For additional information regarding this topic click [http://www.refactoring.com/catalog/hideDelegate.html here] | |||
'''''Inline Class (Opposite Of Extract Class)''''' | |||
If a class is not doing much work it can be merged with a another class. This happens most of the times because of refactoring a class when the class is almost stripped off most of its functionalities. For additional information regarding this topic click [http://www.refactoring.com/catalog/inlineClass.html here] | |||
'''''Introduce Foreign Method''''' | |||
Generally in commercial applications we are not provided with the server code but just the server API. We may sometimes need to add another method i.e. to add another service. If the method is used just once then it is acceptable to write it in the client side, but in case we need to use the method several times, then a method can be created on the client side for hat functionality. If we need just one or two methods then we use this refactor else we use the next one. For additional information regarding this topic click [http://www.refactoring.com/catalog/introduceForeignMethod.html here] | |||
'''''Introduce Local Extension''''' | |||
This is a more general style of the “Introduce Foreign Method” and is used for exactly the same reasons. The only difference being that in case we need just one or two methods, we use the “Introduce Foreign Method”, else we use this method. Here we create a new class which contains these methods and make it a sub class of the original class. This helps in keeping all the methods together in one place. For additional information regarding this topic click [http://www.refactoring.com/catalog/introduceLocalExtension.html here] | |||
'''''Move Field''''' | |||
This is used when a field in a class is used another class more than the class in which it was defined. Solution is to move the field in the class which uses it the most and make the appropriate changes in the methods which use that field. For additional information regarding this topic click [http://www.refactoring.com/catalog/moveField.html here] | |||
'''''Move Method''''' | |||
It is similar to the “Move Field” refactor and is used if a method is used by another class more than the class in which it was defined. Solution is to move the method in the class which uses it the most and then either change the old method into a delegate or remove it. For additional information regarding this topic click [http://www.refactoring.com/catalog/moveMethod.html here] | |||
'''''Remove Middle Man (Opposite Of Hide Delegate)''''' | |||
If the client is doing a lot of delegation work then whenever a feature is added in the server, a delegating method has to be added for that feature which is cumbersome of the additions tend to grow with time and the class seems to be doing delegating work more than it own. So in that case it is better to remove the delegating methods and make the client call the delegate directly. For additional information regarding this topic click [http://www.refactoring.com/catalog/removeMiddleMan.html here] | |||
==='''Organizing Data'''=== | |||
These set of refactoring methods are all about proper organization of the member functions and fields in an object oriented environment. They may initially seem unnecessary, for example getter() and setter() methods which not many use in short programs but in large commercial object orients code they go a long way in keeping the code well organized. | |||
'''''Example''''' | |||
''' Before''' | |||
Class Order | |||
{ | |||
int orderNumber; | |||
String customerName; | |||
String customerAddress; | |||
int customerPhone; | |||
} | |||
'''After''' | |||
Class Order | |||
{ | |||
int orderNumber; | |||
Customer customer; | |||
} | |||
Class Customer | |||
{ | |||
String customerName; | |||
String customerAddress; | |||
int customerPhone; | |||
} | |||
'''''Self Encapsulate Field''''' | |||
Self encapsulating, which is in simple terms, adding getter() and setter() methods for the fields have a few advantages. In inheritance when the sub class wants to change the values of the base class with values computed in the sub class, these methods can be overridden. It is also used to implement lazy initialization (initializing the field only when needed to). For additional information regarding this topic click[http://www.refactoring.com/catalog/selfEncapsulateField.html here] | |||
''''Replace Data Value with Object''''' | |||
In the early stages of program, the simple facts were represented as data items but as the program gets bigger need may arise to include more details. This is made easy if the data item is converted into an object which helps in adding much more detail about the data. For additional information regarding this topic click [http://www.refactoring.com/catalog/replaceDataValueWithObject.html here] | |||
'''''Change Value To Reference''''' | |||
If a value object needs to be allowed to have changeable data and the change need to propagate to every item referring to it, then this refactoring should be used. For additional information regarding this topic click [http://www.refactoring.com/catalog/changeValueToReference.html here] | |||
'''''Change Reference To Value''''' | |||
This is the opposite case from Change Value To Reference. If the reference value is immutable and small, it may as well be changed to a value object. For additional information regarding this topic click [http://www.refactoring.com/catalog/changeReferenceToValue.html here] | |||
'''''Replace Array With Object''''' | |||
An array is supposed to hold similar object but if an array is being used to hold different types of items then it should probably be replaced with an object, i.e. a new class should be formed for that array. In array, the first item may be used to store name, second may be used to store address and so on. It may not be easy to remember this conventions and is not transparent. So replacing it with a class is recommended. For additional information regarding this topic click [http://www.refactoring.com/catalog/replaceArrayWithObject.html here] | |||
'''''Duplicate Observed Data''''' | |||
IN the case of GUI applications where domain data is there in a GUI control and if the domain methods need access to the domain data then we have to use this refactoring method. General method is to copy the data to a domain object and use observer to synchronize the data at the two locations. For additional information regarding this topic click [http://www.refactoring.com/catalog/duplicateObservedData.html here] | |||
''''' Change Unidirectional Association To Bidirectional ''''' | |||
If we have 2 classes and BOTH need to use each other’s features, but only one class has a connection to the other. We need to add a connection from the other class to this class and change modifiers to reflect this. We need this because we may start with two classes in which one refers the other but over time find out that the referred class may now need to access to the objects that refer to it. For additional information regarding this topic click [http://www.refactoring.com/catalog/changeUnidirectionalAssociationToBidirectional.html here] | |||
'''''Change Bidirectional Association To Unidirectional''''' | |||
In this case, one of the classes may no longer need to refer to the other class objects. In that case the unrequired association may be dropped. Bidirectional associations are complex to maintain because care has to be maintained that objects are properly created and destroyed. They also lead to zombie objects in which the object which was supposed to have been reclaimed was not because of a stray reference which was not cleared. For additional information regarding this topic click [http://www.refactoring.com/catalog/changeBidirectionalAssociationToUnidirectional.html here] | |||
'''''Replace Magic Number with Symbolic Constant''''' | |||
If a literal has a specific meaning then it is wise to create a constant with appropriate name. For additional information regarding this topic click [http://www.refactoring.com/catalog/replaceMagicNumberWithSymbolicConstant.html here] | |||
'''''Encapsulate Field''''' | |||
Change a public field to private and provide accessers instead. For encapsulation (data hiding). We do not want changes to be made to the data without the object’s knowledge. For additional information regarding this topic click [http://www.refactoring.com/catalog/encapsulateField.html here] | |||
'''''Encapsulate Collection''''' | |||
On similar lines along the 'Encapsulate Field' it is used to hide the collection from being changed from outside. Create a method which returns a read only view of the collection and we can provide getter() setter() methods for the collection. For additional information regarding this topic click [http://www.refactoring.com/catalog/encapsulateCollection.html here] | |||
'''''Replace Record With Data Class''''' | |||
Sometimes while dealing with legacy codes, we have to bring data records. In these cases its wise to create a dumb object (class) for the record set and provide mutators (getters and setters) for each data member. This case is similar to the Replace Array With Object. For additional information regarding this topic click [http://www.refactoring.com/catalog/replaceRecordWithDataClass.html here] | |||
'''''Replace Type Code With Class''''' | |||
We know them better in C by ‘enums’. A new class can be formed with different fields for each value. One important thing to note is that we can do this only when the enumerations do not affect the behavior of the class. If they do, we have to use the next refactor method. For additional information regarding this topic click [http://www.refactoring.com/catalog/replaceTypeCodeWithClass.html here] | |||
'''''Replace Type Code With Subclasses''''' | |||
If the enumerations affect the behavior, we replace them with sub classes. We take the class which has the type code (enumeration) and create a sub class for each type code. But sometimes we cannot do this (subclass) when either the value of the typecode changes after creation or if the class is already subclasses. In that case we have to use the next refactor method. For additional information regarding this topic click [http://www.refactoring.com/catalog/replaceTypeCodeWithSubclasses.html here] | |||
'''''Replace Type Code With State/Strategy''''' | |||
In this case we replace the type code with a state object. For additional information regarding this topic click [http://www.refactoring.com/catalog/replaceTypeCodeWithStateStrategy.html here] | |||
'''''Replace Subclass With Fields''''' | |||
If we have subclasses which differ in their methods only by their return values, its good to change the methods to superclass fields and remove the subclass altogether. For additional information regarding this topic click [http://www.refactoring.com/catalog/replaceSubclassWithFields.html here] | |||
Line 23: | Line 232: | ||
Conditional expressions form a major part of programming. It is inconceivable to come across any non trivial program that does not make use of conditional expressions. However, several times it so happens that the purpose of a conditional expression is unclear, the expression is either long or can be replaced altogether by another programming construct or technique. There are several refactoring methods whose aim is to simplify conditional expressions. | Conditional expressions form a major part of programming. It is inconceivable to come across any non trivial program that does not make use of conditional expressions. However, several times it so happens that the purpose of a conditional expression is unclear, the expression is either long or can be replaced altogether by another programming construct or technique. There are several refactoring methods whose aim is to simplify conditional expressions. | ||
'''''Example''''' | |||
''' Before''' | |||
if(total>70){ | if(total>70){ | ||
Line 36: | Line 245: | ||
} | } | ||
''' After''' | |||
if(total>70){ | if(total>70){ | ||
Line 70: | Line 279: | ||
There are cases where in different actions need to be taken depending on the type of the object. In such cases it is advisable to replace conditional expressions with polymorphism. For additional information regarding this topic click [http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html here]. | There are cases where in different actions need to be taken depending on the type of the object. In such cases it is advisable to replace conditional expressions with polymorphism. For additional information regarding this topic click [http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html here]. | ||
=== '''Making Method Calls Simpler''' === | === '''Making Method Calls Simpler''' === | ||
Any program written in the object oriented paradigm has several method calls. Simplifying method calls is an important part of refactoring. | Any program written in the object oriented paradigm has several method calls. Simplifying method calls is an important part of refactoring. | ||
'''''Example''''' | |||
''' Before''' | |||
int square(int base) | int square(int base) | ||
int cube(int base) | int cube(int base) | ||
''' After''' | |||
int raiseToPower(int base, int power) | int raiseToPower(int base, int power) | ||
Line 143: | Line 347: | ||
=== '''Dealing with Generalization''' === | |||
Inheritance is an important part of object oriented programming. Proper use of inheritance will result in code that is efficient and easy to understand. Refactoring to deal with generalization is an important category of refactoring techniques. | |||
'''''Example''''' | |||
''' Before''' | |||
Class Employee{ | Class Employee{ | ||
Line 166: | Line 372: | ||
} | } | ||
''' After''' | |||
Class Employee{ | Class Employee{ | ||
Line 231: | Line 437: | ||
In case we are using delegation and are adjusting a majority of the methods to delegate to a different class, we can make the delegating class a subclass of the delegate. For additional information regarding this topic click [http://www.refactoring.com/catalog/replaceDelegationWithInheritance.html here]. | In case we are using delegation and are adjusting a majority of the methods to delegate to a different class, we can make the delegating class a subclass of the delegate. For additional information regarding this topic click [http://www.refactoring.com/catalog/replaceDelegationWithInheritance.html here]. | ||
== Categorizing Refactoring according to what Patterns they lead to== | |||
In addition there are refactoring techniques that are used to ensure that the code conforms to certain design patterns. The refactoring techniques that fall under this category are as follows. | |||
*Chain Constructors | |||
*Compose Method | |||
*Encapsulate Classes with Factory | |||
*Encapsulate Composite with Builder | |||
*Extract Adapter | |||
*Extract Composite | |||
*Extract Parameter | |||
*Form Template Method | |||
*Inline Singleton | |||
*Introduce Null Object | |||
*Introduce Polymorphic Creation With Factory Method | |||
*Limit Instantiation with Singleton | |||
*Move Accumulation to Collecting Parameter | |||
*Move Accumulation to Visitor | |||
*Move Creation Knowledge to Factory | |||
*Move Embellishment to Decorator | |||
*Replace Conditional Dispatcher with Command | |||
*Replace Conditional Logic with Strategy | |||
*Replace Constructors with Creation Methods | |||
*Replace Hard-Coded Notifications with Observer | |||
*Replace Implicit Language with Interpreter | |||
*Replace Implicit Tree with Composite | |||
*Replace One/Many Distinctions with Composite | |||
*Replace State-Altering Conditionals with State | |||
*Replace Type Code with Class | |||
*Unify Interfaces with Adapter | |||
*Unify Interfaces | |||
Additional information about refactoring to patterns can be found [http://industriallogic.com/xp/refactoring/catalog.html here] | |||
== References == | |||
*Refactoring: Improving the Design of Existing Code by Martin Fowler, Kent Beck, John Brant,William Opdyke, Don Roberts | |||
*Refactoring to Patterns Catalog http://industriallogic.com/xp/refactoring/catalog.html | |||
*Refactoring http://sourcemaking.com/refactoring |
Latest revision as of 13:46, 12 September 2009
Categorization of refactoring
Problem Statement
The list of refactoring has become quite long. But people don't remember long lists very well. To promote learning the different patterns, they should be categorized in some way, or perhaps, along various dimensions. Take the list of refactoring available at refactoring.org (and/or elsewhere) and categorize them along as many different dimensions as makes sense. Write up a description of the refactoring landscape.
What is Refactoring?
Refactoring is the process of modifying/rewriting the code of a computer program to change its internal structure without changing its external (functional) behavior in order to improve its internal or external software quality attributes. In simple terms, it is used to improve its readability, reusability or structure without affecting its meaning or behavior.
Why is refactoring required?
If a program code is poorly designed it will be difficult to understand it and therefore maintain it. This fact is made worse for commercial programs which are huge and much more complex to write. These commercial programs are most of the times created and maintained by more than one programmer and have a much greater life span than smaller programs. So these codes should be easy to understand and as a result easy to modify when the need arises. But if the design of the code is not optimum then understanding the code and hence changing/adding new features can be very complex for someone who has not written the code. Moreover the changes may be detrimental to the code. For example if there is high coupling then changing the code at one place may adversely affect the code at some other place. If correct coding practices are not followed then that may lead to security concerns.The main reasons for refactoring are as follows:
- Improving the design of the code
- Makes the code easier to understand
- Makes debugging easier (since the code is easier to understand)
- Code runs faster
Categorizing Refactoring Techniques According to Broad Goals
Refactoring techniques can be classified according to the broad goals they intend to achieve. The different categories are as follows.
Composing Methods
The refactoring methods coming under this basically deal with composing new methods to package the code properly. Most come from the method, class etc being too long and not representing its true functionality or trying to do a lot of things at once. So modularization is the key goal here.
Example
Before
void printDetails(Employee e) { System.out.println(e.id); System.out.println(e.name); Address addr = e.getAddress(); System.out.println(addr.street); System.out.println(addr.city); System.out.println(addr.zip); System.out.println(addr.state); }
After
void printDetails(Employee e) { System.out.println(e.id); System.out.println(e.name); printAddress(e.getAddress()); }
void printAddress(Address addr) { System.out.println(addr.street); System.out.println(addr.city); System.out.println(addr.zip); System.out.println(addr.state); }
Extract Method Code fragment which can be grouped together so create a new method whose name explains the purpose of the method.Used when a method is too long or when it starts needing comments to reveal its purpose (and so is not self explanatory). For additional information regarding this topic click here
Inline Method Used when a method’s body is as clear as the name of the method. Executed by putting the method's body into the body of its callers and remove the method.Sometimes the method body is so concise and clear that we would want to define the method in place and get rid of the method. For additional information regarding this topic click here
Introduce Explaining Variable If there is a complicated expression, put the result into a temporary variable with a meaninigful name.To make the expression and thus the code easier to understand. For additional information regarding this topic click here
Replace Temp With Query Instead of using a temporary variable to hold the result of an experession replace them with a method(query) and replace the expressions with the query method. This refactoring method is used as a preparation of the normal Extract Method refactoring method mainly because the existence of several temporary variables tend to make the ‘extracted’ method quite long since we have to pass them along to the extracted method. (But if the variable is assigned to more than once then consider the next method Split Temp Variable). For additional information regarding this topic click here
Split Temporary Variable If we have a temporary variable assigned to more than once, but is not a loop variable nor a collecting temporary variable. Make a separate temporary variable for each assignment.Some temporary variable (like ‘i’ in for loops) are just plalceholders for each iteration. On the other hand some temp variables are used to hold values of long expressions. Now if that variable is assigned again, it means that the variable more than one responsibility which is discouraged for a temporary variable. Any variable with more than one responsibility should be replaced with a temp for each responsibility. Using a temp for two different things is very confusing for the reader. For additional information regarding this topic click here
Remove Assignment To Parameter If the code assigns to a passed in parameter, use temp variable instead.In Java assigning to a parameter which is a primitive object (int, char etc, not objects) is fine because they are passed by reference. When objects are passed, the reference to the object is passed by value(not the copy of object, but copy of reference to original object). Hence if the reference is reassigned (e.g. swapping) that makes no change to original object but if the passed reference is used to reassign the member variables of the passed object, that may pose problems. Moreover any language which uses pass by reference will have problems if passed parameters are reassigned. For additional information regarding this topic click here
Replace Method With Method Object As we saw earlier, having a long list of local variable hinders the use of Extract Method. We overcame this earlier by Extract Temp with Query but sometimes breaking a method is not possible. So instead of breaking the method, we create an object out of the method so the local variables become fields which are now easily accessible. For additional information regarding this topic click here
Substitute Algorithm It is one of the simplest to execute in which an algorithm in a method is replaced with another set of more coherent and lucid algorithm just because we found a an easier algorithm for a set of code. For additional information regarding this topic click here
Moving features between objects
Object oriented programming is all about objects and their attributes and responsibilities. But creating object structure and deciding where to put the responsibility is tricky. So once created, need may arise due to more insight or due to testing of the classes that these attributes may need to be changed. These refactorings come under this category.
Example
Before
Class Employee { String name; int officeAreaCode; int officeNumber; int residenceAreaCode; int residenceNumber; }
After
Class Employee { String name; TelephoneNumber residencePhone; TelephoneNumber officePhone; }
Class TelephoneNumber { int areaCode; int phoneNumber; }
Extract Class We have a class which has more responsibility than it should have (which may include both attributes and methods). So we can create a new class by taking out some features which can be separated from the existing class.Large sized classes are not easy to comprehend and lead us away from the concept of abstraction. For additional information regarding this topic click here
Hide Delegate (Opposite Of Remove Middle Man) The client should know and thus be very less dependent on the server code for execution. If a client calls a method defined on a field of the server directly then any changes which have to be made on this delegate has to be propogated to the client which is not desirable. So a delegating method can be added on server which limits the change to the client whenever a change is made to the server. For additional information regarding this topic click here
Inline Class (Opposite Of Extract Class) If a class is not doing much work it can be merged with a another class. This happens most of the times because of refactoring a class when the class is almost stripped off most of its functionalities. For additional information regarding this topic click here
Introduce Foreign Method Generally in commercial applications we are not provided with the server code but just the server API. We may sometimes need to add another method i.e. to add another service. If the method is used just once then it is acceptable to write it in the client side, but in case we need to use the method several times, then a method can be created on the client side for hat functionality. If we need just one or two methods then we use this refactor else we use the next one. For additional information regarding this topic click here
Introduce Local Extension This is a more general style of the “Introduce Foreign Method” and is used for exactly the same reasons. The only difference being that in case we need just one or two methods, we use the “Introduce Foreign Method”, else we use this method. Here we create a new class which contains these methods and make it a sub class of the original class. This helps in keeping all the methods together in one place. For additional information regarding this topic click here
Move Field This is used when a field in a class is used another class more than the class in which it was defined. Solution is to move the field in the class which uses it the most and make the appropriate changes in the methods which use that field. For additional information regarding this topic click here
Move Method It is similar to the “Move Field” refactor and is used if a method is used by another class more than the class in which it was defined. Solution is to move the method in the class which uses it the most and then either change the old method into a delegate or remove it. For additional information regarding this topic click here
Remove Middle Man (Opposite Of Hide Delegate) If the client is doing a lot of delegation work then whenever a feature is added in the server, a delegating method has to be added for that feature which is cumbersome of the additions tend to grow with time and the class seems to be doing delegating work more than it own. So in that case it is better to remove the delegating methods and make the client call the delegate directly. For additional information regarding this topic click here
Organizing Data
These set of refactoring methods are all about proper organization of the member functions and fields in an object oriented environment. They may initially seem unnecessary, for example getter() and setter() methods which not many use in short programs but in large commercial object orients code they go a long way in keeping the code well organized.
Example
Before
Class Order { int orderNumber; String customerName; String customerAddress; int customerPhone; }
After
Class Order { int orderNumber; Customer customer; }
Class Customer { String customerName; String customerAddress; int customerPhone; }
Self Encapsulate Field
Self encapsulating, which is in simple terms, adding getter() and setter() methods for the fields have a few advantages. In inheritance when the sub class wants to change the values of the base class with values computed in the sub class, these methods can be overridden. It is also used to implement lazy initialization (initializing the field only when needed to). For additional information regarding this topic clickhere
'Replace Data Value with Object In the early stages of program, the simple facts were represented as data items but as the program gets bigger need may arise to include more details. This is made easy if the data item is converted into an object which helps in adding much more detail about the data. For additional information regarding this topic click here
Change Value To Reference If a value object needs to be allowed to have changeable data and the change need to propagate to every item referring to it, then this refactoring should be used. For additional information regarding this topic click here
Change Reference To Value This is the opposite case from Change Value To Reference. If the reference value is immutable and small, it may as well be changed to a value object. For additional information regarding this topic click here
Replace Array With Object An array is supposed to hold similar object but if an array is being used to hold different types of items then it should probably be replaced with an object, i.e. a new class should be formed for that array. In array, the first item may be used to store name, second may be used to store address and so on. It may not be easy to remember this conventions and is not transparent. So replacing it with a class is recommended. For additional information regarding this topic click here
Duplicate Observed Data IN the case of GUI applications where domain data is there in a GUI control and if the domain methods need access to the domain data then we have to use this refactoring method. General method is to copy the data to a domain object and use observer to synchronize the data at the two locations. For additional information regarding this topic click here
Change Unidirectional Association To Bidirectional If we have 2 classes and BOTH need to use each other’s features, but only one class has a connection to the other. We need to add a connection from the other class to this class and change modifiers to reflect this. We need this because we may start with two classes in which one refers the other but over time find out that the referred class may now need to access to the objects that refer to it. For additional information regarding this topic click here
Change Bidirectional Association To Unidirectional In this case, one of the classes may no longer need to refer to the other class objects. In that case the unrequired association may be dropped. Bidirectional associations are complex to maintain because care has to be maintained that objects are properly created and destroyed. They also lead to zombie objects in which the object which was supposed to have been reclaimed was not because of a stray reference which was not cleared. For additional information regarding this topic click here
Replace Magic Number with Symbolic Constant If a literal has a specific meaning then it is wise to create a constant with appropriate name. For additional information regarding this topic click here
Encapsulate Field Change a public field to private and provide accessers instead. For encapsulation (data hiding). We do not want changes to be made to the data without the object’s knowledge. For additional information regarding this topic click here
Encapsulate Collection On similar lines along the 'Encapsulate Field' it is used to hide the collection from being changed from outside. Create a method which returns a read only view of the collection and we can provide getter() setter() methods for the collection. For additional information regarding this topic click here
Replace Record With Data Class Sometimes while dealing with legacy codes, we have to bring data records. In these cases its wise to create a dumb object (class) for the record set and provide mutators (getters and setters) for each data member. This case is similar to the Replace Array With Object. For additional information regarding this topic click here
Replace Type Code With Class We know them better in C by ‘enums’. A new class can be formed with different fields for each value. One important thing to note is that we can do this only when the enumerations do not affect the behavior of the class. If they do, we have to use the next refactor method. For additional information regarding this topic click here
Replace Type Code With Subclasses If the enumerations affect the behavior, we replace them with sub classes. We take the class which has the type code (enumeration) and create a sub class for each type code. But sometimes we cannot do this (subclass) when either the value of the typecode changes after creation or if the class is already subclasses. In that case we have to use the next refactor method. For additional information regarding this topic click here
Replace Type Code With State/Strategy In this case we replace the type code with a state object. For additional information regarding this topic click here
Replace Subclass With Fields If we have subclasses which differ in their methods only by their return values, its good to change the methods to superclass fields and remove the subclass altogether. For additional information regarding this topic click here
Simplifying Conditional Expressions
Conditional expressions form a major part of programming. It is inconceivable to come across any non trivial program that does not make use of conditional expressions. However, several times it so happens that the purpose of a conditional expression is unclear, the expression is either long or can be replaced altogether by another programming construct or technique. There are several refactoring methods whose aim is to simplify conditional expressions.
Example
Before
if(total>70){ award(“grade A”); updateRecords(); } else{ award(“grade B”); updateRecords(); }
After
if(total>70){ award(“grade A”); } else{ award(“grade B”); } updateRecords();
Decompose Conditional
This refactoring method aims to simplify a complicated conditional expression. This is done by extracting the logic present in the conditional expression, then clause and else clause into different methods. For additional information regarding this topic click here.
Consolidate Conditional Expression
When there are several conditional tests executed sequentially with the same results then they can be consolidated into a single conditional expression and the logic in each of the tests can be extracted into a method.For additional information regarding this topic click here.
Consolidate duplicate conditional expressions
This is in case the same fragment of code is present in all branches of a conditional expression. In such cases this fragment of code can be brought outside the conditional constructs.For additional information regarding this topic click here.
Remove Control Flags
Often, when we have a conditional expression in a loop we have a control flag that checks to see how long the loop should continue. However, the logic and purpose of the loop and conditional expression become a lot clearer when we replace the control flag with break, return and continue statements. For additional information regarding this topic click here.
Replace Nested Conditional With Guard Clauses
It is often advisable to replace nested conditional statements with guard clauses since this would make it easier to follow the logic and purpose of the conditional expressions.For additional information regarding this topic click here.
Replacing Conditional with polymorphism
There are cases where in different actions need to be taken depending on the type of the object. In such cases it is advisable to replace conditional expressions with polymorphism. For additional information regarding this topic click here.
Making Method Calls Simpler
Any program written in the object oriented paradigm has several method calls. Simplifying method calls is an important part of refactoring.
Example
Before
int square(int base) int cube(int base)
After
int raiseToPower(int base, int power)
Rename Method
It is very important that a method name give a clear idea of the purpose of the method. The method name should not be too long, but at the same time it should convey a clear idea as to what the method accomplishes. For additional information regarding this topic click here.
Add or Remove Parameters
When a method requires more parameters in order to perform its function we add a parameter to the method. Similar when a method no longer requires a parameter it should be removed. Without having all the required parameters the method cannot achieve its purpose. Having more methods than necessary can confuse the users about how the method actually works. For additional information regarding this topic click here or here.
Separate Query from Modifiers
We can sometimes have a method that both returns a value and changes the state of an object. In such cases we should have two methods. One, that returns a value and another that changes the state of the object. For additional information regarding this topic click here.
Parameterize Method
We might have methods that do essentially the same tasks that differ slightly based on the values used in the method body. In such cases we should consolidate such methods into a single method that takes the values as parameters. For additional information regarding this topic click here.
Replace Parameters with Explicit Methods
When we have a method that executes different blocks of code depending on the value of one of its parameters we should replace this method with a separate method for each value of the parameter. For additional information regarding this topic click here.
Preserve Whole Object
When we retrieve several values from an object and pass these values as parameters to a method call we should pass the object itself as a parameter to the method call. The necessary values are retrieved from the object in the body of the method. For additional information regarding this topic click here.
Replace Parameter with Method
We come across situations where an object invokes a method and passes the return value as a parameter to a different method. We should modify the code such that the receiver itself invokes the corresponding method instead of accepting its return value as a parameter. This results in the list of parameters of the receiver method becoming shorter. For additional information regarding this topic click here.
Introduce Parameter Object
We have a method that has a list of parameters that can be logically grouped into a single unit. In such cases we can replace the list of parameters with an object. For additional information regarding this topic click here.
Remove Setters for fields that are immutable
We should not have any setter methods for fields that are immutable. Such fields are initialized with a value and retain the value throughout. For additional information regarding this topic click here.
Hide Method
In case we feel that the visibility of a method is greater than required we need to reduce its visibility. We should always try to reduce the visibility of methods as much as possible. For additional information regarding this topic click here.
Replace Constructor with Factory Method
We do this when we want more than just simple construction when we create a method. An example is when different subclasses of the object need to be created based on different conditions. For additional information regarding this topic click here.
Replace Error Codes with Exceptions
Most of the modern programming languages offer support for exceptions. Thus, we should make use of this facility and replace error codes such as returning “-1” with the appropriate exceptions. For additional information regarding this topic click here.
Dealing with Generalization
Inheritance is an important part of object oriented programming. Proper use of inheritance will result in code that is efficient and easy to understand. Refactoring to deal with generalization is an important category of refactoring techniques.
Example
Before
Class Employee{ int empid; }
Class Salesman extends Employee{ float salary; // Other fields and methods } }
Class Manager extends Employee{ float salary; // Other fields and methods }
After
Class Employee{ int empid; float salary; } Class Salesman extends Employee{ //Other fields and methods }
Class Manager extends Employee{ //Other fields and methods }
Collapse Hierarchy
A superclass and subclass that are not very different can be merger together. For additional information regarding this topic click here.
Pull Up Field
In case all the subclasses of a superclass have a common field, the field can be moved to the superclass. For additional information regarding this topic click here.
Pull Up Method
In case all the subclasses of a superclass have a common method, the method can be moved to the superclass. For additional information regarding this topic click here.
Pull up constructor body
In case we have subclass constructors with identical bodies, the body of the subclass constructors can be extracted to the constructor of the superclass. For additional information regarding this topic click here.
Push Down Method
In case certain aspects of the superclass behavior are relevant only for some of its subclasses, the behavior can be extracted into a method of the corresponding subclasses. For additional information regarding this topic click here.
Push Down Field
In case a field is used only by some subclasses of a superclass, the field can be moved to the subclasses that actually use it. For additional information regarding this topic click here.
Extract Subclass
In case a class has features that are used only in some instances then a subclass can be created for these features. For additional information regarding this topic click here.
Extract Superclass
In case two classes have common features a superclass can be created and common features can be moved to the superclass. For additional information regarding this topic click here.
Extract Interface
In case several clients use a common subset of a class’s interface then that subset can be extracted into a separate interface. For additional information regarding this topic click here.
Form Template Method
We have two or more methods in subclasses that perform similar steps in the same order but the steps are different. In this case we can extract these steps into methods of the same signature. Since these methods now have the same signature, the original method which contained the steps extracted into these methods and the newly formed methods can all be pulled up. For additional information regarding this topic click here.
Replace Inheritance with Delegation
In case a subclass uses only a subset of the super class’s interface we can create a field for the superclass and adjust methods in the subclass to delegate to the superclass where required. We can then remove the subclassing. For additional information regarding this topic click here.
Replace Delegation with Inheritance
In case we are using delegation and are adjusting a majority of the methods to delegate to a different class, we can make the delegating class a subclass of the delegate. For additional information regarding this topic click here.
Categorizing Refactoring according to what Patterns they lead to
In addition there are refactoring techniques that are used to ensure that the code conforms to certain design patterns. The refactoring techniques that fall under this category are as follows.
- Chain Constructors
- Compose Method
- Encapsulate Classes with Factory
- Encapsulate Composite with Builder
- Extract Adapter
- Extract Composite
- Extract Parameter
- Form Template Method
- Inline Singleton
- Introduce Null Object
- Introduce Polymorphic Creation With Factory Method
- Limit Instantiation with Singleton
- Move Accumulation to Collecting Parameter
- Move Accumulation to Visitor
- Move Creation Knowledge to Factory
- Move Embellishment to Decorator
- Replace Conditional Dispatcher with Command
- Replace Conditional Logic with Strategy
- Replace Constructors with Creation Methods
- Replace Hard-Coded Notifications with Observer
- Replace Implicit Language with Interpreter
- Replace Implicit Tree with Composite
- Replace One/Many Distinctions with Composite
- Replace State-Altering Conditionals with State
- Replace Type Code with Class
- Unify Interfaces with Adapter
- Unify Interfaces
Additional information about refactoring to patterns can be found here
References
- Refactoring: Improving the Design of Existing Code by Martin Fowler, Kent Beck, John Brant,William Opdyke, Don Roberts
- Refactoring to Patterns Catalog http://industriallogic.com/xp/refactoring/catalog.html
- Refactoring http://sourcemaking.com/refactoring