Contenu connexe
Similaire à Lecture28 (20)
Plus de liufabin 66688 (20)
Lecture28
- 1. Goals of Lecture
• Cover Refactoring
Lecture 28: Refactoring – Background
– Examples
Kenneth M. Anderson
Object-Oriented Analysis and Design
CSCI 6448 - Spring Semester, 2001
April 26, 2001 © Kenneth M. Anderson, 2001 2
What is Refactoring (Very) Simple Example
• Consolidate Duplicate Conditional Fragments (page 243); This
• Refactoring is the process of changing a if (isSpecialDeal()) {
software system such that total = price * 0.95;
send()
– the external behavior of the system does not } else {
total = price * 0.98;
change send()
}
– but the internal structure of the system is • becomes this
improved if (isSpecialDeal()) {
total = price * 0.95;
• This is sometimes called } else {
total = price * 0.98;
– “Improving the design after it has been written” }
send();
April 26, 2001 © Kenneth M. Anderson, 2001 3 April 26, 2001 © Kenneth M. Anderson, 2001 4
- 2. Refactoring is thus Dangerous! Refactoring is Useful Too
• Manager’s point-of-view • Essentially, it is acknowledging the fact that it will be
difficult to get a design right the first time
– If my programmers spend time “cleaning up the – and as a program’s requirements change, the design may need to
code” then that’s less time implementing change
required functionality (and my schedule is • refactoring provides techniques for evolving the design in small
incremental steps
slipping as it is!) • Benefits
• To address this concern – Often code size is reduced after a refactoring
– Confusing structures are transformed into simpler structures
– Refactoring needs to be systematic, incremental, • which are easier to maintain and understand
and safe
April 26, 2001 © Kenneth M. Anderson, 2001 5 April 26, 2001 © Kenneth M. Anderson, 2001 6
A “cookbook” can be useful Principles in Refactoring
• New Book • Fowler’s definition
– Refactoring: Improving the Design of Existing – Refactoring (noun)
Code • a change made to the internal structure of software
• by Martin Fowler (and Kent Beck, John Brant, to make it easier to understand and cheaper to
William Opdyke, and Don Roberts) modify without changing its observable behavior
• Similar to the Gang of Four’s Design – Refactoring (verb)
Patterns • to restructure software by applying a series of
refactorings without changing its observable
– Provides “refactoring patterns” behavior
April 26, 2001 © Kenneth M. Anderson, 2001 7 April 26, 2001 © Kenneth M. Anderson, 2001 8
- 3. Principles, continued Principles, continued
• The purpose of refactoring is • When you systematically apply refactoring,
– to make software easier to understand and you wear two hats
modify – adding function
• contrast this with performance optimization • functionality is added to the system without
spending any time cleaning the code
– again functionality is not changed, only internal
structure; however performance optimizations – refactoring
often involve making code harder to understand • no functionality is added, but the code is cleaned up,
made easier to understand and modify, and
(but faster!)
sometimes is reduced in size
April 26, 2001 © Kenneth M. Anderson, 2001 9 April 26, 2001 © Kenneth M. Anderson, 2001 10
Principles, continued Why should you refactor?
• How do you make refactoring safe? • Refactoring improves the design of software
– without refactoring, a design will “decay” as people make changes
– First, use refactoring “patterns” to a software system
• Fowler’s book assigns “names” to refactorings in the same way • Refactoring makes software easier to understand
that the GoF’s book assigned names to patterns
– because structure is improved, duplicated code is eliminated, etc.
– Second, test constantly! • Refactoring helps you find bugs
• This ties into the extreme programming paradigm, you write – Refactoring promotes a deep understanding of the code at hand,
tests before you write code, after you refactor code, you run the and this understanding aids the programmer in finding bugs and
tests and make sure they all still pass anticipating potential bugs
– if a test fails, the refactoring broke something, but you know • Refactoring helps you program faster
about it right away and can fix the problem before you move on
– because a good design enables progress
April 26, 2001 © Kenneth M. Anderson, 2001 11 April 26, 2001 © Kenneth M. Anderson, 2001 12
- 4. When should you refactor? Problems with Refactoring
• The Rule of Three • Databases
– Three strikes and you refactor – Business applications are often tightly coupled
– refers to duplication of code to underlying databases
• code is easy to change; databases are not
• Refactor when you add function
– Changing Interfaces
– to make it easier to add the function
• Some refactorings require that interfaces be changed
– or to clean things up after the function is added
– Design Changes that are difficult to refactor
• Refactor when you need to fix a bug • This is why Extreme Programming says that
• Refactor as you do a code review software engineers need to have “courage”!
April 26, 2001 © Kenneth M. Anderson, 2001 13 April 26, 2001 © Kenneth M. Anderson, 2001 14
Refactoring: Where to Start? Bad Smells in Code
• How do you identify code that needs to be • Duplicated Code
refactored? – bad because if you modify one instance of
– Fowler uses an olfactory analogy (attributed to duplicated code but not the others, you have
Kent Beck) introduced a bug!
– Look for “Bad Smells” in Code • Long Method
• A very valuable chapter in Fowler’s book – long methods are more difficult to understand;
• It presents examples of “bad smells” and then performance concerns with respect to lots of
suggests refactoring techniques to apply short methods are largely obsolete
April 26, 2001 © Kenneth M. Anderson, 2001 15 April 26, 2001 © Kenneth M. Anderson, 2001 16
- 5. Bad Smells in Code Bad Smells in Code
• Large Class • Shotgun Surgery
– Large classes try to do too much, which reduces – a change requires lots of little changes in a lot of
cohesion different classes
• Long Parameter List • Feature Envy
– hard to understand, can become inconsistent – A method requires lots of information from some other
• Divergent Change class (move it closer!)
– Deals with cohesion; symptom: one type of change • Data Clumps
requires changing one subset of methods; another type – attributes that clump together but are not part of the
of change requires changing another subset same class
April 26, 2001 © Kenneth M. Anderson, 2001 17 April 26, 2001 © Kenneth M. Anderson, 2001 18
Bad Smells in Code Bad Smells in Code
• Primitive Obsession • Lazy Class
– characterized by a reluctance to use classes instead of – A class that no longer “pays its way”
primitive data types • e.g. may be a class that was downsized by refactoring, or
represented planned functionality that did not pan out
• Switch Statements
– Switch statements are often duplicated in code; they can • Speculative Generality
typically be replaced by use of polymorphism (let OO – “Oh I think we need the ability to do this kind of thing
do your selection for you!) someday”
• Parallel Inheritance Hierarchies • Temporary Field
– Similar to Shotgun Surgery; each time I add a subclass – An attribute of an object is only set in certain
to one hierarchy, I need to do it for all related circumstances; but an object should need all of its
hierarchies attributes
April 26, 2001 © Kenneth M. Anderson, 2001 19 April 26, 2001 © Kenneth M. Anderson, 2001 20
- 6. Bad Smells in Code Bad Smells in Code
• Message Chains • Alternative Classes with Different
– a client asks an object for another object and then asks Interfaces
that object for another object etc. Bad because client
depends on the structure of the navigation – Symptom: Two or more methods do the same
• Middle Man thing but have different signature for what they
– If a class is delegating more than half of its do
responsibilities to another class, do you really need it?
• Incomplete Library Class
• Inappropriate Intimacy
– Pairs of classes that know too much about each other’s – A framework class doesn’t do everything you
private details need
April 26, 2001 © Kenneth M. Anderson, 2001 21 April 26, 2001 © Kenneth M. Anderson, 2001 22
Bad Smells in Code The Catalog
• Data Class • The refactoring book has 72 refactoring
– These are classes that have fields, getting and setting patterns!
methods for the fields, and nothing else; they are dumb
data holders, but objects should be about data AND – I’m only going to cover a few of the more
process common ones, including
• Refused Bequest • Extract Method
– A subclass ignores most of the functionality provided • Replace Temp with Query
by its superclass • Move Method
• Comments (!) • Replace Conditional with Polymorphism
– Comments are sometimes used to hide bad code • Introduce Null Object
April 26, 2001 © Kenneth M. Anderson, 2001 23 April 26, 2001 © Kenneth M. Anderson, 2001 24
- 7. Extract Method Extract Method, continued
void printOwing(double amount) {
• You have a code fragment that can be printBanner()
//print details
grouped together System.out.println(“name: ” + _name);
System.out.println(“amount: ” + amount);
• Turn the fragment into a method whose }
=============================================
name explains the purpose of the fragment void printOwing(double amount) {
printBanner()
printDetails(amount)
• Example, next slide }
void printDetails(double amount) {
System.out.println(“name: ” + _name);
System.out.println(“amount: ” + amount);
}
April 26, 2001 © Kenneth M. Anderson, 2001 25 April 26, 2001 © Kenneth M. Anderson, 2001 26
Replace Temp with Query,
Replace Temp with Query
continued
double basePrice = _quantity * _itemPrice
• You are using a temporary variable to hold if (basePrice > 1000)
return basePrice * 0.95;
the result of an expression else
return basePrice * 0.98;
• Extract the expression into a method; ==============================
if (basePrice() > 1000)
Replace all references to the temp with the return basePrice() * 0.95;
else
expression. The new method can then be return basePrice() * 0.98;
…
used in other methods double basePrice() {
return _quantity * _itemPrice;
• Example, next slide }
April 26, 2001 © Kenneth M. Anderson, 2001 27 April 26, 2001 © Kenneth M. Anderson, 2001 28
- 8. Replace Conditional with
Move Method
Polymorphism
• A method is, or will be, using or used by • You have a conditional that chooses
more features of another class than the class different behavior depending on the type of
on which it is defined an object
• Create a new method with a similar body in • Move each leg of the conditional to an
the class it uses most. Either turn the old overriding method in a subclass. Make the
method into a simple delegation, or remove original method abstract
it altogether
April 26, 2001 © Kenneth M. Anderson, 2001 29 April 26, 2001 © Kenneth M. Anderson, 2001 30
Replace Conditional with Replace Conditional with
Polymorphism, continued Polymorphism, continued
double getSpeed() { Bird
switch (_type) {
case EUROPEAN:
return getBaseSpeed(); getSpeed()
case AFRICAN:
return getBaseSpeed() - getLoadFactor() *
_numberOfCoconuts;
case NORWEGIAN_BLUE: European African Norwegian Blue
return (_isNailed) ? 0 :
getBaseSpeed(_voltage);
} getSpeed() getSpeed() getSpeed()
throw new RuntimeException(“Unreachable”)
}
April 26, 2001 © Kenneth M. Anderson, 2001 31 April 26, 2001 © Kenneth M. Anderson, 2001 32
- 9. Introduce Null Object Introduce Null Object
if (customer.isNull()) {
• Repeated checks for a null value name = “occupant”
} else {
• Replace the null value with a null object name = customer.getName()
}
if (customer == null) { Customer ===========================
name = “occupant” public class nullCustomer {
} else { getName() public String getName() { return “occupant”;}
name = customer.getName() }
} ===========================
if (customer == null) { customer.getName();
… Null Customer
The conditional goes away entirely!!
getName()
April 26, 2001 © Kenneth M. Anderson, 2001 33 April 26, 2001 © Kenneth M. Anderson, 2001 34