How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

65
How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD

Transcript of How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Page 1: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

How and When to do Refactoring

CSE301

University of Sunderland

Harry R. Erwin, PhD

Page 2: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Resources

• Eclipse automates a lot of refactoring (8)).• Fowler, 2000, Refactoring: Improving the Design of

Existing Code, Addison-Wesley. Note: this is available electronically at the library.

• http://www.amazon.com/exec/obidos/tg/detail/-/0321109295/103-4060125-0311065

• http://www.amazon.com/exec/obidos/ASIN/0130648841/103-4060125-0311065

• http://www.refactoring.com/catalog/ • http://www.win.ua.ac.be/~lore/refactoringProject/index.

php

Page 3: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Final Year Project Comments• A few comments on OO programming. Important

refactorings will be in dark blue.– Don't translate a C program into Java. Think objects. – Avoid overusing static fields and methods. That suggests

you're writing a C program in Java. Don't go there.– Use 'move method' to push responsibilities into subclasses.

Students often define methods in the calling classes rather than in the called classes, and then need to correct the design.

– Look for polymorphism. It can be used rather elegantly.– Are you using JUnit and TDD? Use the existing suite and

read the documentation about asserts!

Page 4: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Refactoring that Eclipse Supports Already!

• Rename

• Move

• Change Method Signature

• Convert Anonymous Class to Nested Class

• Change Nested Class to Top-Level Class

• Push Down

• Pull Up

• Extract Interface• Use Supertype Where

Possible• Inline• Extract Method• Extract Local Variable• Extract Constant• Convert Local Variable to

Field• Encapsulate Field

Page 5: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

A Catalog of Refactorings

• Composing Methods

• Moving Features Between Objects

• Organizing Data

• Simplifying Conditionals

• Making Method Calls Simpler

• Generalization

• Big Refactorings

Page 6: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

The Basic Rule of Refactoring

• “Refactor the low hanging fruit” http://c2.com/cgi/wiki?RefactorLowHangingFruit

• Low Hanging Fruit (def): “The thing that gets you most value for the least investment.”

• In other words, don’t spend much time on it. There are ways to improve any design incrementally. We will explore a few of them.

Page 7: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

The Goal of Refactoring

• To improve code without changing what it does.

• This in some ways is similar to how an optimizing compiler restructures code.

• These how-to’s describe things you can do.

• Think about why they work!

Page 8: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Composing Methods

• Extract Method

• Inline Method

• Replace Method with Method Object

• Substitute Algorithm

Page 9: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Extract Method

• Extract Method is one of the most important refactorings. If you see a patch of coherent code that does something like compose a pane in a GUI encapsulate it as a method. This is my favorite refactoring; usually I apply it when a method gets too long.

• Take a clump of related code and make it into a small method. eclipse handles this well.

• It does have problems with local variables….

Page 10: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Example for Extract Methodfinal JCheckBox oos = new JCheckBox(

"Out of Supply ",unit.outOfSupply);ActionListener oosListener = new ActionListener(){

public void actionPerformed(ActionEvent e){theUnit.outOfSupply = oos.isSelected();theBattle.recompute();

}};oos.addActionListener(oosListener);res.add(oos);

Page 11: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

That Code Becomesfinal JCheckBox oos = addOOS(unit, theUnit);res.add(oos);

AND

private JCheckBox addOOS(Ground unit, final Ground theUnit) {final JCheckBox oos = new JCheckBox(

"Out of Supply ",unit.outOfSupply);ActionListener oosListener = new ActionListener(){

public void actionPerformed(ActionEvent e){theUnit.outOfSupply = oos.isSelected();theBattle.recompute();

}};oos.addActionListener(oosListener);return oos;

}

Page 12: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Inline Method Reverses Extract Method

• You use Inline Method when the code the results from Extract Method is uglier than the original.

• You also use it when the method’s body is just as clear as its name.

• Or if you have a group of badly factored methods—inline them and then re-extract methods.

• Remember to get rid of the method—needless indirection is irritating and makes you look dumb.

Page 13: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Replace Method with Method Object

• Replace Method with Method Object moves local variables into class fields of a ‘functor’, so Extract Method can be used more easily.

• The curse of extracting methods is local variables. So introduce method objects if you have a big method with lots of local variables. Applying this refactoring converts all those local variables to fields of the method object.

• Then you can extract methods freely.

Page 14: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Method Object Implementation (after Beck via Fowler)

• Create a new class named after the method.• Define a final field for the object that owned the original

method and a modifiable field for every local variable.• Define a constructor with those fields as arguments.• Give the class a method named ‘compute()’.• Replace the old method with one that creates the object and

calls compute().int gamma(int val1, int val2, int val3) {

return new Gamma(this,val1,val2,val3).compute();}

• Now you can freely decompose compute() without passing any parameters. This is a good thing.

Page 15: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Substitute Algorithm

• This one sounds a bit dumb. Have you thought of a smarter or clearer way of doing something? Go ahead and replace the method with the new algorithm.

• If you’re using test-driven development, you can quickly check whether the new version works. If it doesn’t, backtrack, and nobody will ever know…

Page 16: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Moving Features Between Objects

• A fundamental design decision is where to put responsibilities. You’ll never get it right the first time. Refactoring allows you to change your mind.

• When you want to move functions between objects, these refactorings handle it. Move Method, Move Field, and Extract/Inline Class are the heavyweights here.

Page 17: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Move Field

• “Moving state and behavior between classes is the very essence of refactoring.” (Fowler)

• You do this to shuffle responsibilities around. Consider a move if a field is used more by other classes than by its home class.

• If you do an Extract Class, the fields get moved first and then the methods follow them.

• You may need to encapsulate a field first. Then move the field and point any accessors at the new location, perhaps using new accessors there.

Page 18: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Move Method

• “The bread and butter of refactoring.” (Fowler)• A method is used by another class more than by

its home class. I know of cats like that.• Create a similar method in the other class. Either

convert the old method to a simple delegation or remove it entirely.

• Think about doing this after you’ve moved some fields between classes. Warning: watch for polymorphism on the original class. That can make the move impossible.

Page 19: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Extract Class

• Classes grow, and you may have one class doing work that should be done by two. You find you’re violating the Single Responsibility Principle (SRP) with lots of data and methods. Time to get the scalpel out.

• Create a new class and move the relevant fields and methods there. Delegate!

• If you don’t know why the SRP is important, wait till next semester.

Page 20: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Inline Class

• You find a class isn’t doing very much. This often occurs after a refactoring that has removed fields and methods.

• Move its features into another class and then delete it.

• Use Encapsulate Field, Move Field, and Move Method to do this.

Page 21: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Hide Delegate

• A client calls a method defined on a field of a server object, possibly violating encapsulation.

theServer.getManager().getDepartment();

• To do this, the client needs to know that theServer has a Manager field. Replace with a getDepartment() method for theServer. Then unless getManager() is needed, remove it.

theServer.getDepartment();

Page 22: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Remove Middle Man

• “Here, you take the phone.” After some development, you notice that a class is doing a lot of simple delegation.

• Get the client to call the delegate directly.

• You may need to create an accessor for the delegate, but thereafter a method only needs to call on the delegate.

Page 23: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

End of First Hour

Page 24: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Organizing Data

• These refactorings generally clean up problems with how classes define and access fields.

• The most interesting refactoring here is probably Duplicate Observed Data. That’s how you fix a class that mixes business logic with GUI or SQL code. We’ll spend some time on it since Fowler isn’t very clear.

• By the way, value objects are objects that are equal if their fields are equal—you override equals() and hashCode() for them.

Page 25: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Self Encapsulate Field

• You are accessing a field of a class directly in a method, but use of the field is becoming awkward.

• Create getting and setting methods (‘accessors’) for the field and make the field private. Use these methods within the class.

• Why not always do this? Because getting and setting methods obscure what the code is doing.

• Doing this is particularly important if a subclass may later need to override direct access with a computed value.

• A closely related refactoring: Encapsulate Field.

Page 26: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Replace Data Value with Object

• You find that you have a data item (a primitive or value type) that needs additional data or behavior.

• For example, the data might be a String that has a special format.

• Turn the data item into an object that holds the original data as a final field. Provide a constructor and a getting method. If you need a setting method, have it create a new instance of the class.

• You may need to Change Value to Reference, if multiple instances need to share the data object.

Page 27: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Change Value to Reference• Reference objects stand for one object in the real world.• Value objects are defined entirely through their data values. You

need to know when two are equal, so you have to override equals() and hashCode().

• A class has many instances, many of which have the same value. You want to replace them with a single instance.– Replace the value constructor with a factory method.– Decide how to provide access to the objects.– Decide whether to precreate or create as required.– Alter the factory method to return the reference object.

Page 28: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Change Reference to Value

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

• Turn it into a value object.– Check that it is really immutable (final) or can become immutable.– Create an equals() and a hashCode() method. The easiest way to write

hashCode() is to do a bitwise xor (^) on all the hashcodes of the fields referred to in the equals() method. Primitive types need to be ‘boxed’ for this. E.g., to box i, Integer iBoxed = new Integer(i);

– The consider removing the factory method and replacing it with a public constructor.

– Finally make the contents final.

Page 29: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Replace Array with Object

• You have inherited a design that uses an array where different elements mean different things. This is bad programming practice.

• Replace with an object that has a field for each element.

• You do this by creating getters and setters for each entry in the array, creating the fields, and then removing the array and repointing the getters and setters at the new fields.

Page 30: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Duplicate Observed Data

• This is how you pull a domain model (the business logic) out of a poorly-designed system with no model. If there are multiple windows, see Separate Domain from Presentation.

• Copy the business data in the system to a domain object. Set up observers to synchronize the domain model with whatever is dependent on it.

• This is a tricky dribble, so pay close attention.

Page 31: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

DOD Implementation (Part 1)• Start with the dependent objects (e.g., parts of the GUI,

other interfaces or a database).• Create a domain class as an Observable. Create

references to the dependent objects in the domain class.• Make the dependent objects Observers of the domain

class, so that if it changes, they change. Write an update() method for each. Each constructor has to connect to the domain class, add itself as an Observer of that class, and finally call its update() method on the domain class instance.

• Use Self-Encapsulate Data on any domain data in the dependent objects. Test—behavior should not change.

Page 32: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

DOD Implementation (Part 2)• Now for GUIs, add a method to the event handler that uses the

new setting methods to update the component with its current value using direct access to the field. This ensures user input goes through the setting method. This will be important later. Test.

• Define corresponding data fields and getting/setting methods in the domain class. Setting methods need to trigger model updates and the notify mechanism. Test.

• Redirect the accessors for the dependent classes to read and write the domain class fields. Modify the observer’s update method to copy from the domain fields to the dependent class using direct access. Test one last time.

Page 33: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Change Unidirectional to Bidirectional Association

• You need a backpointer? First, lie down to see if the need passes. If it doesn’t, do the following:– Add a field for the backpointer.– Decide which class controls the link.– Create a helper method on the other side to send back

the backpointer.– If the existing link modifier is on the controlling side,

just modify it to update the backpointers.– If not, have it call a routine on the other side to update

the backpointers.

Page 34: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Change Bidirectional to Unidirectional Association

• Reduce bidirectional to unidirectional whenever possible.

• If nobody needs one direction, simply remove it.• For clients who do need the other direction:

– Try Encapsulate Field on the backpointer– Then try Substitute Algorithm on the getter and test– If clients don’t need the getter, change each to get the

object in the field some other way.– When no reader is left, dump the updater and remove

the backpointer.

Page 35: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Encapsulate Field

• A class field is publically accessible. Hide it.• Some people consider this good programming

practice. Other people find it makes code inefficient or hard to read. YMMV.

• Provide accessors—getField(), setField(arg)• Then find all users and change them to use the

accessors.• Finally, make the field private. This will tell you if

you have really found all the users.• Closely related to Self Encapsulate Field.

Page 36: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Encapsulate Collection

• If a class contains a collection of instances, getters and setters don’t work really well.

• First, initialize an empty collection when you create it. • Encapsulate the collection field to create a getter and setter.• Next provide public methods to add and remove elements.

Modify users to use them instead.• Modify your getter to return a read-only iterator (see the

Collections class for how).• Think about moving code that uses the getter into the class

that owns the collection.

Page 37: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Replace Type Code

• With Class– When a class has a numeric type code that doesn’t

affect its behavior—replace with a new class for each code.

• With Subclasses– If the type code does affect behavior, use subclasses

• With State/Strategy– Or replace the type code with a state object if

subclassing doesn’t work

Page 38: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Replace Subclass with Fields

• You have subclasses that differ only in methods that return constant (final) data.

• Define final fields to contain the data, eliminate the subclasses, and return the field values instead.

Page 39: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Simplifying Conditionals

• These simplify conditional logic (if/then/else). Decompose Conditional is the most important. The elements of an if/then/else are replaced with method calls. These refactorings can also clean up if/then/else messes where flags are used to control sequencing or returns.

• Switch statements should be replaced with polymorphism.

• A null object is a real ‘do-nothing’ object that substitutes for a null value in a reference.

Page 40: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Decompose Conditional

• Suppose you have a complicated if-then-else (or ?:) statement.

• Use Extract Method on the condition, the then part, and the else part.

• If there is a nested conditional, try Replace Nested Conditional with Guard Clauses first.

Page 41: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Consolidate Conditional Expression

• If you have a long list of ‘if(condi) return 0;’ statements in a method, combine them into a single conditional and extract it.

• This does the same thing, is clearer, and sets you up to use Extract Method.

Page 42: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Consolidate Duplicate Conditional Fragments

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

• Then move it outside of the expression.

• This makes things clearer. Consider using Extract Method, too.

Page 43: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Replace Nested Conditional with Guard Clauses

• If a method contains a complicated if-then-else expression that doesn’t make clear what the normal path is, use ‘guard clauses’ for all the special cases.

• Handle each special case with an immediate return. Then execute the normal path.

• Be clear!

Page 44: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Replace Conditional with Polymorphism

• Indicator—you have logic that chooses different behavior based on the type of an object or the value of a flag.

• Consider splitting the behavior among subclasses. Make the original method abstract.

• You may have to replace type codes with subclasses or state/strategy first.

Page 45: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Introduce Null Object

• You’re getting very tired of checking for null. This is often the case for framework code.

• Then replace the null value with a do-nothing ‘null object’. (This is what an Adaptor class is in swing, by the way.)

• This has the advantage of inheriting from Object (or even from the base class of your hierarchy). Unlike null, a ‘null object’ can have do-nothing methods called on it. A lot of if-then-else cases then disappear.

Page 46: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Making Method Calls Simpler

• These refactorings make interfaces more straightforward.

• Rename Method is convenient to document what a method does.

• Most of the remaining refactorings are used to get rid of parameters, but be cautious in concurrent programming.

• Factory methods hide the concrete implementation of an interface.

Page 47: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Rename Method

• You have a method with a name like ‘foo’. Change the name to mean something.

• This is important when you have lots of small methods as a form of documentation.

• eclipse handles this very well.

Page 48: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Separate Query from Modifier

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

• This violates the SRP (discussed later).

• Break the method into two: one returns the value, and the other changes the state.

Page 49: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Preserve Whole Object/Replace Parameter with Method

• You get values from an object and use them as parameters to a method call.

• Why not simply pass the object to the method and let it get its own values? (You can even create a parameter object to do this.)

• If you call a method to get a value to pass as a parameter to a second method, why not let the second method get the parameter?

Page 50: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Replace Constructor with Factory Method

• You find you need to do more than simple construction when you create an object.

• Make the constructor private and replace it with a factory method.

• Factory methods are often static methods that do a smart construction. See the Singleton pattern for an example.

Page 51: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Generalization

• These refactorings clean up inheritance hierarchies. They also allow you to ‘evolve’ the hierarchy.

• Template methods are methods that call private methods that can be subclassed to replace multiple methods with the same signature.

• Sometimes delegation works better than inheritance or vice versa, so don’t be afraid to try it both ways.

Page 52: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Pull Up/Push Down Field/Method

• These refactorings move fields and methods within an inheritance hierarchy to improve the structure and eliminate duplication.

• You may need to rename related fields or methods to do this when they have acquired different names during development.

• Take the method or field code, copy it to the new location, and remove it from the old.

Page 53: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Pull Up Constructor Body

• You have constructors on subclasses that are mostly identical.

• You can’t use Pull Up Method because constructors aren’t inherited. 8)

• Create a superclass constructor containing the common code and call this from the subclass methods using super(args).

Page 54: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Extract Subclass/ Superclass/Interface

• When a class has features that are used only in certain cases, give those features to subclasses. This is similar to Extract Class using delegation. Extract Subclass is usually simpler but more limited than Extract Class.

• Push down the methods first and later the fields. Watch for fields that you can throw away.

• You can also use this to define a ‘null object’.• Extract Superclass is the reverse process.• Extract Interface creates an interface the same way.

Page 55: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Collapse Hierarchy

• After a while, a class hierarchy grows complex. If you refactor it a bit, moving fields and methods around and extracting classes and interfaces, you may discover that some classes no longer do anything useful. Get rid of them.

• Choose a class to sacrifice, move its remaining fields and methods, and kill it. Don’t get blood on your clothes.

Page 56: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Form Template Method

• You have two methods associated with sibling subclasses that perform similar operations in the same order, but the operations are not the same.

• Exploit polymorphism. Extract the operations into methods with the same signature (names and argument lists), so that the original methods become the same. You may need to rename one. Then you can pull the original methods up into a superclass, and the differences live in the subclasses.

Page 57: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Replace Inheritance with Delegation (and vice versa)

• See the discussion of Extract Class versus Extract Subclass.

• A subclass only uses part of a superclass interface or doesn’t use inherited data.

• Change the subclass to a separate class and delegate.

• Or the reverse…• Whatever works.

Page 58: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Big Refactorings

• Tease Apart Inheritance

• Convert Procedural Design to Objects

• Separate Domain from Presentation

• Extract Hierarchy

Page 59: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Tease Apart Inheritance• Your design was by a C++ programmer who believed in

multiple inheritance. 8(• Create two hierarchies from the complex one and use

delegation to invoke one from the other.– The more important of the two responsibilities should define

inheritance in the original tree. – The lesser responsibility should have its own tree. – Link them at the hip (abstract base class to abstract base class)

so that to the outside it looks like a single complex hierarchy.– You may need to Replace Constructor with Factory Method.

Page 60: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Convert Procedural Design to Objects

• Someone who never took CSE301 did an OO design. It looks like a C program 8(.– Turn data into objects. Each record type should become a dumb

data object with get and set operations.– Take all the procedural code and give it to a main class (creating a

big heap of powerful and fertile material, aka BS).– Break up the main class behavior (using a shovel and Extract

Method).– Move the behavior into the objects (using a rake and Move

Method).– Finally delete the original main class, flush it down the sewer, and

celebrate with a beer.

Page 61: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Separate Domain from Presentation

• Someone who never took CSE301 designed a GUI program 8(.– Create a domain class for each window.– If the data on a window forms a grid, create classes for

each row and a collection to hold the rows.– Separate the presentation from the domain using Move

Field and Duplicate Observed Data. – Use Extract Method and Move Method to do the same

for behavior.– Refactor the resulting mess mercilessly to clean up.

Page 62: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Extract Hierarchy

• You have a class that has a zillion special cases since the designer never heard of the SRP or polymorphism 8(.

• Make a list of important special cases. Extend it as you learn more. Take your time to get it right.– Create a subclass for each special case.– Use Replace Constructor with Factory Method to

produce the subclasses.– Methods with conditional logic should Replace

Conditional with Polymorphism or Extract Method.– Refactor mercilessly to clean up.

Page 63: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Beck’s Comments on Putting it all Together

• Even if you know the refactorings, you may not know when to do it. Beck claims there is a rhythm to refactoring.

• Practice it.• You’re getting it when you start to feel confident

that you can take anything that has been screwed up and make it better.

• You’re getting it when you can ‘stop with confidence.’ You’ve done enough. If the code is better, release it. If not, flush it.

Page 64: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

The Feeling You Want

• You have a different relationship with your program. The design is fluid and plastic and under your control. It changes and adapts to changes in your requirements.

• You can feel it.

Page 65: How and When to do Refactoring CSE301 University of Sunderland Harry R. Erwin, PhD.

Learning Refactoring

• Pick a goal—something’s wrong with the program. Resolve to fix it. Then fix it.

• Stop when you’re unsure.• Backtrack. Use test-driven development to make

sure you haven’t broken something. If you have, back up.

• Work with a friend. ‘We explain to each other what we don’t understand.’ You’ll learn a lot in the process.