SlideBoom – collaborative media
Hello, Guest   |   Sign In   |   Sign Up
Home
Presentations
People
Groups
Join Now
Upload


0

No comments posted yet

Comments

Previous page 1-10 of 34 Next page
Previous page 1-10 of 34 Next page
Presentation Notes
Slide 1

http://www.refactoring.com/catalog/index.html

Slide 4

http://www.refactoring.com/catalog/extractMethod.html
You have a code fragment that can be grouped together.
Turn the fragment into a method whose name explains the purpose of the method.

Slide 5

http://www.refactoring.com/catalog/inlineMethod.html
A method's body is just as clear as its name.
Put the method's body into the body of its callers and remove the method.

Slide 6

http://www.refactoring.com/catalog/inlineTemp.html
You have a temp that is assigned to once with a simple expression, and the temp is getting in the way of other refactorings.
Replace all references to that temp with the expression.

Slide 7

http://www.refactoring.com/catalog/replaceTempWithQuery.html
You are using a temporary variable to hold the result of an expression.
Extract the expression into a method. Replace all references to the temp with the expression. The new method can then be used in other methods.

Additional Comments
Side Effects
Paul Haahr pointed out that you can't do this refactoring if the code in between the the assignment to the temp and the use of the temp changes the value of the expression that calculates the temp. In these cases the code is using the temp to snapshot the value of the temp when it's assigned. The name of the temp should convey this fact (and you should change the name if it doesn't).

He also pointed out that it is easy to forget that creating a reference object is a side effect, while creating a value object isn't.

Slide 8

http://www.refactoring.com/catalog/introduceExplainingVariable.html
You have a complicated expression.
Put the result of the expression, or parts of the expression, in a temporary variable with a name that explains the purpose.

Slide 9

http://www.refactoring.com/catalog/splitTemporaryVariable.html
You 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.

Slide 10

http://www.refactoring.com/catalog/removeAssignmentsToParameters.html
The code assigns to a parameter.
Use a temporary variable instead.

Slide 11

http://www.refactoring.com/catalog/replaceMethodWithMethodObject.html
You have a long method that uses local variables in such a way that you cannot apply Extract Method
Turn the method into its own object so that all the local variables become fields on that object. You can then decompose the method into other methods on the same object.

Additional Comments
Using a Static Method
You can do this refactoring with a static method, but in this case you don't need the first field pointing back to the original object.
Alternative Steps with Temps
Marnix Klooster suggested an alternative to the mechanics. Rather than creating fields in the Method Object for all the temps, leave the temps as temps and only turn them into fields as you need to in order to use Extract Method. It means you have to use a special form of Extract Method, but may help in reducing the scope of the temps. Of course you can use Reduce Scope of Variableafterwards on any temp that's only used in one method.

Slide 12

http://www.refactoring.com/catalog/substituteAlgorithm.html
You want to replace an algorithm with one that is clearer.
Replace the body of the method with the new algorithm.

Slide 14

http://www.refactoring.com/catalog/moveMethod.html
A method is, or will be, using or used by more features of another class than the class on which it is defined.
Create a new method with a similar body in the class it uses most. Either turn the old method into a simple delegation, or remove it altogether.

Slide 15

http://www.refactoring.com/catalog/moveField.html
A field is, or will be, used by another class more than the class on which it is defined.
Create a new field in the target class, and change all its users.

Slide 16

http://www.refactoring.com/catalog/extractClass.html ou have one class doing work that should be done by two.
Create a new class and move the relevant fields and methods from the old class into the new class.

Slide 17

http://www.refactoring.com/catalog/inlineClass.html
A class isn't doing very much.
Move all its features into another class and delete it.

Slide 18

http://www.refactoring.com/catalog/hideDelegate.html
A client is calling a delegate class of an object.
Create methods on the server to hide the delegate.

Slide 19

http://www.refactoring.com/catalog/removeMiddleMan.html
A class is doing too much simple delegation.
Get the client to call the delegate directly.

Slide 20

http://www.refactoring.com/catalog/introduceForeignMethod.html
A server class you are using needs an additional method, but you can't modify the class.
Create a method in the client class with an instance of the server class as its first argument.

Slide 21

http://www.refactoring.com/catalog/introduceLocalExtension.html
A server class you are using needs several additional methods, but you can't modify the class.
Create a new class that contains these extra methods. Make this extension class a subclass or a wrapper of the original.

Additional Comments
Using Free Functions in C++
--Andy Glew writes:
I comment on this in the light of the recent comp.lang.c++.moderated discussion of using object.method() or free functions, possibly friends, in a class interface. I.e. this comment is more C++ oriented than Java oriented.
Briefly, if the original class used free functions for this sort of interface, the assymmetry introduced by wrapping a class's object.methods() would not exist. In C++
class MfDateSub { private: Date _original; // wrapping the symmetric operator after(date1,date2) public: friend bool after (MfDateSub arg1, MfDateSub arg2) { return after(arg1._original,arg2._original); } public: friend bool after (MfDateSub arg1, Date arg2) { return after(arg1._original,arg2); } public: friend bool after (Date arg1, MfDateSub arg2) { return after(arg1,arg2._original); } }; Now all combinations work; the wrapping is more invisible to the user.
Even better if the free function after(date1,date2) does not require friendship --- although the definition of the extensions gets spread into a few more places.
Note that in the example above, however, an implicit conversion of a MfDateSub value to a Date would suffice.
class MfDateSub { operator Date() const { return _original } } although this approach cannot always work, e.g. when there is extra data to be compared in the extension.
CONCLUSION: using free functions in an interface allows a greater degree of syntactic transparency when wrapping.
Return type for extra methods
--Dmitri Colebatch wrote in to ask why when using the subclass I didn't return the subclass in the extra methods. So I have added the nextDay method to MfDate, but it returns a Date not an MfDate. I can't think of any good reason to return the superclass, so I agree with him and suggest returning MfDate instead. The same is true for the wrapper implementation as well. After all if the client is using the extra method, they are aware of the new class. This way they avoid having to futz with the returned object if they want to invoke other extension methods.

Slide 24

http://www.refactoring.com/catalog/selfEncapsulateField.html
You are accessing a field directly, but the coupling to the field is becoming awkward.
Create getting and setting methods for the field and use only those to access the field.

Slide 25

http://www.refactoring.com/catalog/replaceDataValueWithObject.html
You have a data item that needs additional data or behavior.
Turn the data item into an object.

Slide 26

http://www.refactoring.com/catalog/changeValueToReference.html
You have a class with many equal instances that you want to replace with a single object.
Turn the object into a reference object.

Slide 27

http://www.refactoring.com/catalog/changeReferenceToValue.html
You have a reference object that is small, immutable, and awkward to manage.
Turn it into a value object.

Slide 28

http://www.refactoring.com/catalog/replaceArrayWithObject.html
You have an array in which certain elements mean different things.
Replace the array with an object that has a field for each element.

Slide 29

http://www.refactoring.com/catalog/duplicateObservedData.html
You have domain data available only in a GUI control, and domain methods need access.
Copy the data to a domain object. Set up an observer to synchronize the two pieces of data.

Slide 30

http://www.refactoring.com/catalog/changeUnidirectionalAssociationToBidirectional.html
You have two classes that need to use each other's features, but there is only a one-way link.
Add back pointers, and change modifiers to update both sets.
Additional Comments
Doing a remove
In the example I showed an addOrder method, but I didn't show the removeOrder method. If you want to do a remove, you would write it like the add method but set the customer to null.

class Customer {
void removeOrder( Order arg ) {
arg.setCustomer( null );
}

}

Slide 31

http://www.refactoring.com/catalog/changeBidirectionalAssociationToUnidirectional.html
ou have a two-way association but one class no longer needs features from the other.
Drop the unneeded end of the association.

Slide 32

http://www.refactoring.com/catalog/replaceMagicNumberWithSymbolicConstant.html
You have a literal number with a particular meaning.
Create a constant, name it after the meaning, and replace the number with it.

Additional Comments
Using a constant method
For this refactoring I used a symbolic constant, which is the most common Java idiom.
However an alternative is the constant method, which is a method of this form

public static double gravitationalConstant() {
return 9.81;
}

This idiom is less familiar to C based programmers, but is very familiar to Smalltalkers (who didn't have constants in their language). On the whole I don't tend to use this in Java as it is less idiomatic to the language. However if you need to replace the simple return with a calculated value then it's worth changing the constant field to a constant method. (I guess there should be a refactoring for that....)

Slide 33

http://www.refactoring.com/catalog/encapsulateField.html
There is a public field.
Make it private and provide assessors.

Slide 34

http://www.refactoring.com/catalog/encapsulateCollection.html
A method returns a collection.
Make it return a read-only view and provide add/remove methods.

Slide 35

http://www.refactoring.com/catalog/replaceRecordWithDataClass.html
You need to interface with a record structure in a traditional programming environment.
Make a dumb data object for the record.

Slide 36

http://www.refactoring.com/catalog/replaceTypeCodeWithClass.html
A class has a numeric type code that does not affect its behavior.
Replace the number with a new class.

Corrections
Privitizing the accessors for the type code
At the end of the refactoring I said that you could make those methods that use the type code, eggetCode(), private. I neglected to say that you first have to find the callers of those methods and change them to no longer use the code number.

Slide 37

http://www.refactoring.com/catalog/replaceTypeCodeWithSubclasses.html
You have an immutable type code that affects the behavior of a class.
Replace the type code with subclasses.

Slide 38

http://www.refactoring.com/catalog/replaceTypeCodeWithStateStrategy.html
You have a type code that affects the behavior of a class, but you cannot use subclassing.
Replace the type code with a state object.

Slide 39

http://www.refactoring.com/catalog/replaceSubclassWithFields.html
You have subclasses that vary only in methods that return constant data.
Change the methods to superclass fields and eliminate the subclasses.

Slide 41

http://www.refactoring.com/catalog/decomposeConditional.html
You have a complicated conditional (if-then-else) statement.
Extract methods from the condition, then part, and else parts.

Slide 42

http://www.refactoring.com/catalog/consolidateConditionalExpression.html
You have a sequence of conditional tests with the same result.
Combine them into a single conditional expression and extract it.

Slide 43

http://www.refactoring.com/catalog/consolidateDuplicateConditionalFragments.html
The same fragment of code is in all branches of a conditional expression.
Move it outside of the expression.
Additional Comments
Using with try/catch blocks
Paul Haahr rightly took me to task for being far too glib when I talked about consolidating with exceptions. You can only pull repeated code into a final block if all non-fatal exceptions are caught. This is because the finally block is executed after any exception, including those that don't have a catch clause. (Of course you may prefer that to happen, but that's not a semantics preserving change.)

Slide 44

http://www.refactoring.com/catalog/removeControlFlag.html
You have a variable that is acting as a control flag for a series of boolean expressions.
Use a break or return instead.

Slide 45

http://www.refactoring.com/catalog/replaceNestedConditionalWithGuardClauses.html
A method has conditional behavior that does not make clear what the normal path of execution is
Use Guard Clauses for all the special cases

Slide 46

http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html
You have a conditional that chooses different behavior depending on the type of an object.
Move each leg of the conditional to an overriding method in a subclass. Make the original method abstract.

Slide 47

http://www.refactoring.com/catalog/introduceNullObject.html
You have repeated checks for a null value.
Replace the null value with a null object.

Slide 48

http://www.refactoring.com/catalog/introduceAssertion.html
A section of code assumes something about the state of the program.
Make the assumption explicit with an assertion.

Slide 49

關於介面(Interface)
參數列合理化:不多、不少剛好是使用端要的
穩定的介面很好,但適合的介面更重要:不要擔心調整介面 signature,舊的介面用 @depurated
萃取出資料泥團(Data Clump),讓介面更清楚表達自身的實質內涵
不斷強化測試,尤其是對介面的測試
介面的定義表達的一個人的溝通能力

Slide 50

關於介面(Interface)
參數列合理化:不多、不少剛好是使用端要的
穩定的介面很好,但適合的介面更重要:不要擔心調整介面 signature,舊的介面用 @depurated
萃取出資料泥團(Data Clump),讓介面更清楚表達自身的實質內涵
不斷強化測試,尤其是對介面的測試
介面的定義表達的一個人的溝通能力

Slide 51

http://www.refactoring.com/catalog/renameMethod.html
The name of a method does not reveal its purpose.
Change the name of the method.

Slide 52

http://www.refactoring.com/catalog/addParameter.html
A method needs more information from its caller.
Add a parameter for an object that can pass on this information.

Slide 53

http://www.refactoring.com/catalog/removeParameter.html
A parameter is no longer used by the method body.
Remove it.

Slide 54

http://www.refactoring.com/catalog/separateQueryFromModifier.html
You have a method that returns a value but also changes the state of an object.
Create two methods, one for the query and one for the modification.

Slide 55

http://www.refactoring.com/catalog/parameterizeMethod.html
Several methods do similar things but with different values contained in the method body.
Create one method that uses a parameter for the different values.

Corrections
Clarifying the Mechanics
I've since (after a suggestion from Prof Kahlbrandt) found better mechanics for this refactoring (changes are in bold)
Create a parameterized method that can be substituted for each repetitive methodCompileReplace the body of one method with a call to the new methodCompile and TestUse Inline Method on the old methodRepeat for all the methods.

Slide 56

http://www.refactoring.com/catalog/replaceParameterWithExplicitMethods.html
You have a method that runs different code depending on the values of an enumerated parameter.
Create a separate method for each value of the parameter.

Slide 57

http://www.refactoring.com/catalog/preserveWholeObject.html
You are getting several values from an object and passing these values as parameters in a method call.
Send the whole object instead.

Slide 58

http://www.refactoring.com/catalog/replaceParameterWithMethod.html
An object invokes a method, then passes the result as a parameter for a method. The receiver can also invoke this method.
Remove the parameter and let the receiver invoke the method.

Slide 59

http://www.refactoring.com/catalog/introduceParameterObject.html
You have a group of parameters that naturally go together.
Replace them with an object.

Additional Comments
Dealing with a chain of calls
Ralph Johnson pointed out to me that a common case isn't clear in the Refactoring book. This case is when you have a bunch of methods that call each other, all of which have a clump of parameters that need this refactoring. In this case you don't want to apply Introduce Parameter Object because it would lead to lots of new objects when you only want to have one object that's passed around.
The approach to use is to start with the head of the call chain and apply Introduce Parameter Object there. Then apply Preserve Whole Object to the other methods.

Slide 60

http://www.refactoring.com/catalog/removeSettingMethod.html
A field should be set at creation time and never altered.
Remove any setting method for that field.

Corrections
Using Final
Paul Haahr kindly pointed out to me that I've not been accurate with the use of final in this refactoring. The point that I missed is that you can't use a final field if the initialization is done in a separate method to the constructor. This the example at the bottom of page 301 (that uses initialize(id)) just does not compile. (My apologies for not testing that fragment, some do slip through the net....) If you want to use a separate method, you can't make the field final
This also means that the mechanics is incorrect. Making the field final should be the last step not the first, and can only be done if it's possible.

Slide 61

http://www.refactoring.com/catalog/hideMethod.html
A method is not used by any other class.
Make the method private.

Slide 62

http://www.refactoring.com/catalog/replaceConstructorWithFactoryMethod.html
You want to do more than simple construction when you create an object.
Replace the constructor with a factory method.

Additional Comments
Dimitri Paltchoun pointed out that as well as using Class.forName() and a string for a client to specify the created class, you can also use the class object itself. This would lead you to method like
static Employee create(Class c){
try{
return (Employee)c.newInstance();
}catch(Exception e){
throw new IllegalException("Unable to instantiate" +c);
}
}
This would be called from this code
Employee.create(Engineer.class);

Slide 63

http://www.refactoring.com/catalog/encapsulateDowncast.html
A method returns an object that needs to be downcasted by its callers.
Move the downcast to within the method.

Slide 64

http://www.refactoring.com/catalog/replaceErrorCodeWithException.html
A method returns a special code to indicate an error.
Throw an exception instead.

Slide 65

http://www.refactoring.com/catalog/replaceExceptionWithTest.html
You are throwing an exception on a condition the caller could have checked first.
Change the caller to make the test first.

Slide 68

http://www.refactoring.com/catalog/pullUpField.html
Two subclasses have the same field.
Move the field to the superclass.

Slide 69

http://www.refactoring.com/catalog/pullUpMethod.html
You have methods with identical results on subclasses.
Move them to the superclass.

Slide 70

http://www.refactoring.com/catalog/pullUpConstructorBody.html
You have constructors on subclasses with mostly identical bodies.
Create a superclass constructor; call this from the subclass methods.

Slide 71

http://www.refactoring.com/catalog/pushDownMethod.html
Behavior on a superclass is relevant only for some of its subclasses.
Move it to those subclasses.

Slide 72

http://www.refactoring.com/catalog/pushDownField.html
A field is used only by some subclasses.
Move the field to those subclasses.

Slide 73

http://www.refactoring.com/catalog/extractSubclass.html
A class has features that are used only in some instances.
Create a subclass for that subset of features.

Slide 74

http://www.refactoring.com/catalog/extractSuperclass.html
You have two classes with similar features.
Create a superclass and move the common features to the superclass.

Slide 75

http://www.refactoring.com/catalog/extractInterface.html
Several clients use the same subset of a class's interface, or two classes have part of their interfaces in common.
Extract the subset into an interface.

Slide 76

http://www.refactoring.com/catalog/collapseHierarchy.html
A superclass and subclass are not very different.
Merge them together.

Slide 77

http://www.refactoring.com/catalog/formTemplateMethod.html
You have two methods in subclasses that perform similar steps in the same order, yet the steps are different.
Get the steps into methods with the same signature, so that the original methods become the same. Then you can pull them up.

Slide 78

http://www.refactoring.com/catalog/replaceInheritanceWithDelegation.html
A subclass uses only part of a superclasses interface or does not want to inherit data.
Create a field for the superclass, adjust methods to delegate to the superclass, and remove the subclassing.

Slide 79

http://www.refactoring.com/catalog/replaceDelegationWithInheritance.html
You're using delegation and are often writing many simple delegations for the entire interface.
Make the delegating class a subclass of the delegate.


Presentation Transcript
Slide 1

Catalog Of Refactoring SOURCE FROM: http://www.refactoring.com/

報告人:高明權
DATE :2008/11/25 Ver 1.00
EMAIL : MCK6214@gmail.com

Slide 2

Catalog Of Refactoring

Composing Methods (#9)
Moving Features Between Objects (#8)
Organizing Data (#16)
Simplifying Conditional Expression (#8)
Making Method Calls Simpler (#15)
Dealing with Generalization (#12)

2

資料來源: http://www.refactoring.com/

Slide 3

Composing Methods

Extract Method
Inline Method
Inline Temp
Replace Temp with Query
Introduce Explaining Variable
Split Temporary Variable
Remove Assignments to Parameters
Replace Method with Method Object
Substitute Algorithm

3

Slide 4

Extract Method

Before


void printOwing() {
printBanner();

//print details
System.out.println ("name: " + _name);
System.out.println ("amount " + getOutstanding());
}

After


void printOwing() {
printBanner();
printDetails(getOutstanding());
}

void printDetails (double outstanding) {
System.out.println ("name: " + _name);
System.out.println ("amount " + outstanding);
}

4

You have a code fragment that can be grouped together

Slide 5

Inline Method

Before


int getRating() {
return (moreThanFiveLateDeliveries()) ? 2 : 1;
}
boolean moreThanFiveLateDeliveries() {
return _numberOfLateDeliveries > 5;
}

After


int getRating() {
return (_numberOfLateDeliveries > 5) ? 2 : 1;
}

5

A method's body is just as clear as its name.

Slide 6

Inline Temp

Before


double basePrice = anOrder.basePrice();
return (basePrice > 1000);

After


return (anOrder.basePrice() > 1000) ;

6

You have a temp that is assigned to once with a simple expression, and the temp is getting in the way of other refactorings.

Slide 7

Replace Temp with Query

Before


double basePrice = _quantity * _itemPrice;
if (basePrice > 1000)
return basePrice * 0.95;
else
return basePrice * 0.98;

After


if (basePrice() > 1000)
return basePrice() * 0.95;
else
return basePrice() * 0.98;
...

double basePrice() {
return _quantity * _itemPrice;
}

7

You are using a temporary variable to hold the result of an expression.

Slide 8

Introduce Explaining Variable

Before


if ( (platform.toUpperCase().indexOf("MAC") > -1) &&
(browser.toUpperCase().indexOf("IE") > -1) &&
wasInitialized() && resize > 0 ) {
// do something
}

After


final boolean isMacOs = platform.toUpperCase().indexOf("MAC") > -1;
final boolean isIEBrowser = browser.toUpperCase().indexOf("IE") > -1;
final boolean wasResized = resize > 0;

if (isMacOs && isIEBrowser && wasResized && wasInitialized() ) {
// do something
}

8

You have a complicated expression.

Slide 9

Split Temporary Variable

Before


double temp = 2 * (_height + _width);
System.out.println (temp);
temp = _height * _width;
System.out.println (temp);

After


final double perimeter = 2 * (_height + _width);
System.out.println (perimeter);
final double area = _height * _width;
System.out.println (area);

9

You have a temporary variable assigned to more than once, but is not a loop variable nor a collecting temporary variable.

Slide 10

Remove Assignments to Parameters

Before


int discount (int inputVal, int quantity, int yearToDate) {
if (inputVal > 50) inputVal -= 2;
...
}

After


int discount (int inputVal, int quantity, int yearToDate) {
int result = inputVal;
if (inputVal > 50) result -= 2;
...
}

10

The code assigns to a parameter.

Slide 11

Replace Method with Method Object

Before


class Order {
double price() {
double primaryBasePrice;
double secondaryBasePrice;
double tertiaryBasePrice;
// long computation;
...
}
...
}

After

11

You have a long method that uses local variables in such a way that you cannot apply Extract Method

Slide 12

Substitute Algorithm

Before


String foundPerson(String[] people){
for (int i = 0; i < people.length; i++) {
if (people[i].equals ("Don")){
return "Don";
}
if (people[i].equals ("John")){
return "John";
}
if (people[i].equals ("Kent")){
return "Kent";
}
}
return "";
}

After


String foundPerson(String[] people){
List candidates = Arrays.asList(new String[] {"Don", "John", "Kent"});
for (int i=0; i<people.length; i++)
if (candidates.contains(people[i]))
return people[i];
return "";
}

12

You want to replace an algorithm with one that is clearer.

Slide 13

Moving Features Between Objects

Move Method
Move Field
Extract Class
Inline Class
Hide Delegate
Remove Middle Man
Introduce Foreign Method
Introduce Local Extension

13

Slide 14

Move Method

Before


class Project {
Person[] participants;
}
class Person {
int id;
boolean participate(Project p) {
for(int i=0; i<p.participants.length; i++) {
if (p.participants[i].id == id) return(true);
}
return(false);
}
}

... if (x.participate(p)) ...

After


class Project {
Person[] participants;
boolean participate(Person x) {
for(int i=0; i<participants.length; i++) {
if (participants[i].id == x.id) return(true);
}
return(false);
}
}
class Person {
int id;
}

... if (p.participate(x)) ...

14

A method is, or will be, using or used by more features of another class than the class on which it is defined.

Slide 15

Move Field

Before

After

15

A field is, or will be, used by another class more than the class on which it is defined.

Slide 16

Extract Class

Before

After

16

You have one class doing work that should be done by two.

Slide 17

Inline Class

Before

After

17

A class isn't doing very much.

Slide 18

Hide Delegate

Before

After

18

A client is calling a delegate class of an object.

Slide 19

Remove Middle Man

Before

After

19

A class is doing too much simple delegation.

Slide 20

Introduce Foreign Method

Before


Date newStart = new Date(previousEnd.getYear(),
previousEnd.getMonth(),
previousEnd.getDate() + 1);

After


Date newStart = nextDay(previousEnd);

private static Date nextDay(Date arg) {
return new Date (arg.getYear(),arg.getMonth(), arg.getDate() + 1);
}

20

A server class you are using needs an additional method, but you can't modify the class.

Slide 21

Introduce Local Extension

Before

After

21

A server class you are using needs several additional methods, but you can't modify the class.

Slide 22

Organizing Data 1/2

Self Encapsulate Field
Replace Data Value with Object
Change Value to Reference
Change Reference to Value
Replace Array with Object
Duplicate Observed Data
Change Unidirectional Association to Bidirectional
Change Bidirectional Association to Unidirectional

22

Slide 23

Organizing Data 2/2

Replace Magic Number with Symbolic Constant
Encapsulate Field
Encapsulate Collection
Replace Record with Data Class
Replace Type Code with Class
Replace Type Code with Subclasses
Replace Type Code with State/Strategy
Replace Subclass with Fields

23

Slide 24

Self Encapsulate Field

Before


private int _low, _high;
boolean includes (int arg) {
return arg >= _low && arg <= _high;
}

After


private int _low, _high;
boolean includes (int arg) {
return arg >= getLow() && arg <= getHigh();
}
int getLow() {
return _low;
}
int getHigh() {
return _high;
}

24

You are accessing a field directly, but the coupling to the field is becoming awkward.

Slide 25

Replace Data Value with Object

Before

After

25

You have a data item that needs additional data or behavior.

Slide 26

Change Value to Reference

Before

After

26

You have a class with many equal instances that you want to replace with a single object.

Slide 27

Change Reference to Value

Before

After

27

You have a reference object that is small, immutable, and awkward to manage.

Slide 28

Replace Array with Object

Before


String[] row = new String[3];
row [0] = "Liverpool";
row [1] = "15";

After


Performance row = new Performance();
row.setName("Liverpool");
row.setWins("15");

28

You have an array in which certain elements mean different things.

Slide 29

Duplicate Observed Data

Before

After

29

You have domain data available only in a GUI control, and domain methods need access.

Slide 30

Change Unidirectional Association to Bidirectional

Before

After

30

You have two classes that need to use each other's features, but there is only a one-way link.

Slide 31

Change Bidirectional Association to Unidirectional

Before

After

31

You have a two-way association but one class no longer needs features from the other.

Slide 32

Replace Magic Number with Symbolic Constant

Before


double potentialEnergy(double mass, double height) {
return mass * height * 9.81;
}

After


double potentialEnergy(double mass, double height) {
return mass * GRAVITATIONAL_CONSTANT * height;
}
static final double GRAVITATIONAL_CONSTANT = 9.81;

32

You have a literal number with a particular meaning.

Slide 33

Encapsulate Field

Before


public String _name;

After


private String _name;
public String getName() {
return _name;
}
public void setName(String arg) {
_name = arg;
}

33

There is a public field.

Slide 34

Encapsulate Collection

Before

After

34

A method returns a collection.

Slide 35

Replace Record with Data Class

Before

After

35

You need to interface with a record structure in a traditional programming environment.

Slide 36

Replace Type Code with Class

Before

After

36

A class has a numeric type code that does not affect its behavior.

Slide 37

Replace Type Code with Subclasses

Before

After

37

You have an immutable type code that affects the behavior of a class.

Slide 38

Replace Type Code with State/Strategy

Before

After

38

You have a type code that affects the behavior of a class, but you cannot use subclassing.

Slide 39

Replace Subclass with Fields

Before

After

39

You have subclasses that vary only in methods that return constant data.

Slide 40

Simplifying Conditional Expression

Decompose Conditional
Consolidate Conditional Expression
Consolidate Duplicate Conditional Fragments
Remove Control Flag
Replace Nested Conditional with Guard Clauses
Replace Conditional with Polymorphism
Introduce Null Object
Introduce Assertion

40

Slide 41

Decompose Conditional

Before


if (date.before (SUMMER_START) || date.after(SUMMER_END))
charge = quantity * _winterRate + _winterServiceCharge;
else
charge = quantity * _summerRate;

After


if (notSummer(date))
charge = winterCharge(quantity);
else
charge = summerCharge(quantity);

41

You have a complicated conditional (if-then-else) statement.

Slide 42

Consolidate Conditional Expression

Before


double disabilityAmount() {
if (_seniority < 2) return 0;
if (_monthsDisabled > 12) return 0;
if (_isPartTime) return 0;
// compute the disability amount
...
}

After


double disabilityAmount() {
if (isNotEligableForDisability()) return 0;
// compute the disability amount
...
}

42

You have a sequence of conditional tests with the same result.

Slide 43

Consolidate Duplicate Conditional Fragments

Before


if (isSpecialDeal()) {
total = price * 0.95;
send();
} else {
total = price * 0.98;
send();
}

After


if (isSpecialDeal())
total = price * 0.95;
else
total = price * 0.98;
send();

43

The same fragment of code is in all branches of a conditional expression.

Slide 44

Remove Control Flag

Before

After

44

You have a variable that is acting as a control flag for a series of boolean expressions.

Slide 45

Replace Nested Conditional with Guard Clauses

Before


double getPayAmount() {
double result;
if (_isDead) result = deadAmount();
else {
if (_isSeparated)
result = separatedAmount();
else {
if (_isRetired) result = retiredAmount();
else result = normalPayAmount();
};
}
return result;
};

After


double getPayAmount() {
if (_isDead) return deadAmount();
if (_isSeparated) return separatedAmount();
if (_isRetired) return retiredAmount();
return normalPayAmount();
};

45

A method has conditional behavior that does not make clear what the normal path of execution is

Slide 46

Replace Conditional with Polymorphism

Before


double getSpeed() {
switch (_type) {
case EUROPEAN:
return getBaseSpeed();
case AFRICAN:
return getBaseSpeed() - getLoadFactor() * _numberOfCoconuts;
case NORWEGIAN_BLUE:
return (_isNailed) ? 0 : getBaseSpeed(_voltage);
}
throw new RuntimeException ("Should be unreachable");
}

After

46

You have a conditional that chooses different behavior depending on the type of an object.

Slide 47

Introduce Null Object

Before


if (customer == null)
plan = BillingPlan.basic();
else
plan = customer.getPlan();

After

47

You have repeated checks for a null value.

Slide 48

Introduce Assertion

Before


double getExpenseLimit() {
// should have either expense limit or a primary project
return (_expenseLimit != NULL_EXPENSE) ?
_expenseLimit:
_primaryProject.getMemberExpenseLimit();
}

After


double getExpenseLimit() {
Assert.isTrue (_expenseLimit != NULL_EXPENSE || _primaryProject != null);
return (_expenseLimit != NULL_EXPENSE) ?
_expenseLimit:
_primaryProject.getMemberExpenseLimit();
}

48

A section of code assumes something about the state of the program.

Slide 49

Making Method Calls Simpler 1/2

Rename Method
Add Parameter
Remove Parameter
Separate Query from Modifier
Parameterize Method
Replace Parameter with Explicit Methods
Reserve Whole Object
Replace Parameter with Method

49

Slide 50

Making Method Calls Simpler 2/2

Introduce Parameter Object
Remove Setting Method
Hide Method
Replace Constructor with Factory Method
Encapsulate Downcast
Replace Error Code with Exception
Replace Exception with Test

50

Slide 51

Rename Method

Before

After

51

The name of a method does not reveal its purpose.

Slide 52

Add Parameter

Before

After

52

A method needs more information from its caller.

Slide 53

Remove Parameter

Before

After

53

A parameter is no longer used by the method body.

Slide 54

Separate Query from Modifier

Before

After

54

You have a method that returns a value but also changes the state of an object.

Slide 55

Parameterize Method

Before

After

55

Several methods do similar things but with different values contained in the method body.

Slide 56

Replace Parameter with Explicit Methods

Before


void setValue (String name, int value) {
if (name.equals("height")) {
_height = value;
return;
}
if (name.equals("width")) {
_width = value;
return;
}
Assert.shouldNeverReachHere();
}

After


void setHeight(int arg) {
_height = arg;
}
void setWidth (int arg) {
_width = arg;
}

56

You have a method that runs different code depending on the values of an enumerated parameter.

Slide 57

Reserve Whole Object

Before


int low = daysTempRange().getLow();
int high = daysTempRange().getHigh();
withinPlan = plan.withinRange(low, high);

After


withinPlan = plan.withinRange(daysTempRange());

57

You are getting several values from an object and passing these values as parameters in a method call.

Slide 58

Replace Parameter with Method

Before


int basePrice = _quantity * _itemPrice;
discountLevel = getDiscountLevel();
double finalPrice = discountedPrice (basePrice, discountLevel);

After


int basePrice = _quantity * _itemPrice;
double finalPrice = discountedPrice (basePrice);

58

An object invokes a method, then passes the result as a parameter for a method. The receiver can also invoke this method.

Slide 59

Introduce Parameter Object

Before

After

59

You have a group of parameters that naturally go together.

Slide 60

Remove Setting Method

Before

After

60

A field should be set at creation time and never altered.

Slide 61

Hide Method

Before

After

61

A method is not used by any other class.

Slide 62

Replace Constructor with Factory Method

Before


Employee (int type) {
_type = type;
}

After


static Employee create(int type) {
return new Employee(type);
}

62

You want to do more than simple construction when you create an object.

Slide 63

Encapsulate Downcast

Before


Object lastReading() {
return readings.lastElement();
}

After


Reading lastReading() {
return (Reading) readings.lastElement();
}

63

A method returns an object that needs to be downcasted by its callers.

Slide 64

Replace Error Code with Exception

Before


int withdraw(int amount) {
if (amount > _balance)
return -1;
else {
_balance -= amount;
return 0;
}
}

After


void withdraw(int amount) throws BalanceException {
if (amount > _balance) throw new BalanceException();
_balance -= amount;
}

64

A method returns a special code to indicate an error.

Slide 65

Replace Exception with Test

Before


double getValueForPeriod (int periodNumber) {
try {
return _values[periodNumber];
} catch (ArrayIndexOutOfBoundsException e) {
return 0;
}
}

After


double getValueForPeriod (int periodNumber) {
if (periodNumber >= _values.length) return 0;
return _values[periodNumber];
}

65

You are throwing an exception on a condition the caller could have checked first.

Slide 66

Dealing with Generalization 1/2

Pull Up Field
Pull Up Method
Pull Up Constructor Body
Push Down Method
Push Down Field
Extract Subclass
Extract Superclass
Extract Interface

66

Slide 67

Dealing with Generalization 2/2

Collapse Hierarchy
Form Template Method
Replace Inheritance with Delegation
Replace Delegation with Inheritance

67

Slide 68

Pull Up Field

Before

After

68

Two subclasses have the same field.

Slide 69

Pull Up Method

Before

After

69

You have methods with identical results on subclasses.

Slide 70

Pull Up Constructor Body

Before


class Manager extends Employee...
public Manager (String name, String id, int grade) {
_name = name;
_id = id;
_grade = grade;
}
...
}

After


class Manager extends Employee...
public Manager (String name, String id, int grade) {
super (name, id);
_grade = grade;
}
...
}

70

You have constructors on subclasses with mostly identical bodies.

Slide 71

Push Down Method

Before

After

71

Behavior on a superclass is relevant only for some of its subclasses.

Slide 72

Push Down Field

Before

After

72



Slide 73

Extract Subclass

Before

After

73

A class has features that are used only in some instances.

Slide 74

Extract Superclass

Before

After

74

You have two classes with similar features.

Slide 75

Extract Interface

Before

After

75

Several clients use the same subset of a class's interface, or two classes have part of their interfaces in common.

Slide 76

Collapse Hierarchy

Before

After

76

A superclass and subclass are not very different.

Slide 77

Form Template Method

Before

After

77

You have two methods in subclasses that perform similar steps in the same order, yet the steps are different.

Slide 78

Replace Inheritance with Delegation

Before

After

78

A subclass uses only part of a superclasses interface or does not want to inherit data.

Slide 79

Replace Delegation with Inheritance

Before

After

79

You're using delegation and are often writing many simple delegations for the entire interface.

Slide 80

善用但不濫用重構!

Catalog Of Refactoring

Author: tommykao Added: 1 month ago Topic: Computers

17 Views    1 Embeds    Language: English