Refactoring Refactoring, applied - Purdue Universityprogram’s code is not structured in a...

20
1 C Refactoring Martin Fowler (and Kent Beck, John Brant, William Opdyke, Don Roberts), Refactoring- Improving the Design of Existing Code Addison Wesley 1999 CS510 S o f t w a r e E n g i n e e r Code, Addison Wesley, 1999. Refactoring (noun): a change made to the internal structure of software to make it easier to understand and 1 r i n g January 20, 2008 cheaper to modify without changing its observable behavior. Refactor (verb): to restructure software by applying a series of refactorings. C Refactoring, applied Straight from the book: CS510 S o f t w a r e E n g i n e e r “a program to calculate and print a statement of a customer’s charges at a video store” ...price depends on how long the movie is rented and the category of the movie 2 r i n g January 20, 2008 ...also compute frequent renter points C Refactoring: Movie Class diagram of the starting point classes. CS510 S o f t w a r e E n g i n e e r * 1 3 r i n g January 20, 2008 O b j e c t Refactoring: Movie Class public class Movie Movie { public static final int CHILDREN=2; public static final int REGULARS=0; public static final int public void setPriceCode(int arg) { _priceCode = arg; } O r i e n t e d S o f t w a r e E n g public static final int NEW_RELEASE=1; private String _title; private int _priceCode; public Movie(String title, int priceCode) { _title=title; priceCode = priceCode; public String getTitle() { return _title; } } January 20, 2008 4 g i n e e r i n g } public int getPriceCode() { return _priceCode; }

Transcript of Refactoring Refactoring, applied - Purdue Universityprogram’s code is not structured in a...

Page 1: Refactoring Refactoring, applied - Purdue Universityprogram’s code is not structured in a convenient way to add it, refactor the code. C Refactoring: step 1 Write a test suite !

1

C

Refactoring

Martin Fowler (and Kent Beck, John Brant, William Opdyke, Don Roberts), Refactoring- Improving the Design of Existing Code Addison Wesley 1999

CS510 S o f t w

a r e E n g i n e e r

Code, Addison Wesley, 1999.

Refactoring (noun): a change made to the internal structure of software to make it

easier to understand and

1

r i n g

January 20, 2008

cheaper to modify without changing its observable behavior.

Refactor (verb): to restructure software by applying a series of refactorings.

C

Refactoring, applied

Straight from the book:

CS510 S o f t w

a r e E n g i n e e r

“a program to calculate and print a statement of a customer’s charges at a video store”

...price depends on how long the movie is rented and the category of the movie

2

r i n g

January 20, 2008

...also compute frequent renter points

C

Refactoring: Movie

Class diagram of the starting point classes.

CS510 S o f t w

a r e E n g i n e e r

*

1

3

r i n g

January 20, 2008

O b j e c t

Refactoring: Movie Classpublic class MovieMovie {

public static final int CHILDREN=2;public static final int REGULARS=0;public static final int

public void setPriceCode(int arg) {_priceCode = arg;

}

O r i e n t e d S o f t w

a r e E n g

public static final int NEW_RELEASE=1;

private String _title;private int _priceCode;

public Movie(String title, int priceCode) {

_title=title;priceCode = priceCode;

public String getTitle() {return _title;

}}

January 20, 2008 4

g i n e e r i n g

_p p}public int getPriceCode() {

return _priceCode;}

Page 2: Refactoring Refactoring, applied - Purdue Universityprogram’s code is not structured in a convenient way to add it, refactor the code. C Refactoring: step 1 Write a test suite !

2

O b j e c t

Refactoring: Rental Classpublic class RentalRental {

private Movie _movie;private int _daysRented;

O r i e n t e d S o f t w

a r e E n g

public Rental(Movie movie, int daysRented) {

_movie = movie;_daysRented = daysRented ;

}public int getDaysRented() {

return _daysRented ;}public Movie getMovie() {

t i

January 20, 2008 5

g i n e e r i n g

return _movie;}

}

O b j e c t

Refactoring: Customer Classpublic class CustomerCustomer {

private String _name;private Vector _rentals =new Vector();

O r i e n t e d S o f t w

a r e E n g

public Customer(String name) {_name = name;

}public void addRental(Rental arg) {

_rentals.addElement(arg);}public String getName() {

return _name;}

January 20, 2008 6

g i n e e r i n g

O b j e c t

Refactoring: Customer Classpublic class CustomerCustomer...

public String statement() {double totalAmount = 0; O

r i e n t e d S o f t w a r e E

n g

double totalAmount = 0;int frequentRenterPoints = 0;Enumeration rentals = _rental.elements();String result = “Rental Record for “ + getName() + “\n”;while (rentals.hasMoreElements()) {

double thisAmount = 0;Rental each = (Rental) rentals.nextElement();

// determine amounts for each lineswitch (each.getMovie().getPriceCode()) {

January 20, 2008 7

g i n e e r i n g

switch (each.getMovie().getPriceCode()) {case Movie.REGULAR:

thisAmount += 2;if (each.getDaysRented() > 2)

thisAmount+=(each.getDaysRented()-2) * 1.5;

break;

O b j e c t

Refactoring: Customer Classpublic class CustomerCustomer

public String statement() ...

case Movie NEW RELEASE: O r i e n t e d S o f t w

a r e E n g

case Movie.NEW_RELEASE:thisAmount += each.getDaysRented() * 3;break;

case Movie.CHILDRENS:thisAmount += 1.5;if (each.getDaysRented() > 3)

thisAmount+=(each.getDaysRented()-3) * 1.5;

break;}

January 20, 2008 8

g i n e e r i n g

// add frequent renter pointsfrequentRenterPoints ++;// add bonus for a two day new release rentalif ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE)&&

each.getDaysRented() > 1) frequentRenterPoints++;

Page 3: Refactoring Refactoring, applied - Purdue Universityprogram’s code is not structured in a convenient way to add it, refactor the code. C Refactoring: step 1 Write a test suite !

3

O b j e c t

Refactoring: Customer Classpublic class CustomerCustomer

public String statement() ...

//show figures for this rental O r i e n t e d S o f t w

a r e E n g

// gresult += “\t” + each.getMovie().getTitle()+ “\t” +

String.valueOf(thisAmount) + “\n”;totalAmount += thisAmount;

}// add footer linesresult += “Amount owed is “+Sting.valueOf(totalAmount) + “\n”;result += “You earned “+Sting.valueOf(frequentRenterPoints)

+ “frequent renter points\n”;return result;

}

January 20, 2008 9

g i n e e r i n g

}

C

Refactoring

Interaction diagram for the statement method.

CS510 S o f t w

a r e E n g i n e e r

10

r i n g

January 20, 2008

C

Refactoring: problem statement

CS510 S o f t w

a r e E n g i n e e r

Add a htmlStatment method which returns a customer statement string containing html tags.

...and there will be some changes to the way movies are classified

affecting frequent renter points and charging

11

r i n g

January 20, 2008

...affecting frequent renter points and charging.

When you find you have to add a feature to a program, and the program’s code is not structured in a convenient way to add it, refactor the code.

CRefactoring: step 1

Write a test suite !

CS510 S o f t w

a r e E n g i n e e r

Refactoring should not affect the outcome of tests. The test suite must exercise the published interface of the classes.

Obviously, refactoring should not affect the published interface. So, avoid publishing interfaces too early.

12

r i n g

January 20, 2008

f , p g f y

Page 4: Refactoring Refactoring, applied - Purdue Universityprogram’s code is not structured in a convenient way to add it, refactor the code. C Refactoring: step 1 Write a test suite !

4

C

Refactoring: step 2statement() is overly long, apply the Extract Method refactoring

public String statement() {double totalAmount = 0;C

S510 S o f t w a r e E

n g i n e e r

int frequentRenterPoints = 0;Enumeration rentals = _rental.elements();String result = “Rental Record for “ + getName() + “\n”;while (rentals.hasMoreElements()) {

double thisAmount = 0;Rental each = (Rental) rentals.nextElement();// determine amounts for each lineswitch (each.getMovie().getPriceCode()) {

case Movie.REGULAR:thisAmount += 2;if (each.getDaysRented() > 2)

thisAmount+=(each.getDaysRented()-2) * 1.5;b k

13

r i n g

January 20, 2008

break; case Movie.NEW_RELEASE:

thisAmount += each.getDaysRented() * 3; break;case Movie.CHILDRENS:

thisAmount += 1.5;if (each.getDaysRented() > 3)

thisAmount+=(each.getDaysRented()-3) * 1.5;break;

}

C

Refactoring: step 2public String statement() {

double totalAmount = 0;int frequentRenterPoints = 0;Enumeration rentals = _rental.elements();String result = “Rental Record for “ + getName() + “\n”;while (rentals.hasMoreElements()) {

CS510 S o f t w

a r e E n g i n e e r

while (rentals.hasMoreElements()) {double thisAmount = 0;Rental each = (Rental) rentals.nextElement();

thisAmount = amountFor(each);// add frequent renter pointsfrequentRenterPoints ++;// add bonus for a two day new release rentalif ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE)&&

each.getDaysRented() > 1) frequentRenterPoints++;//show figures for this rentalresult += “\t” + each.getMovie().getTitle()+ “\t” +

String.valueOf(thisAmount) + “\n”;

14

r i n g

January 20, 2008

totalAmount += thisAmount;}// add footer linesresult += “Amount owed is “+Sting.valueOf(totalAmount) + “\n”; result += “You

earned “+Sting.valueOf(frequentRenterPoints) + “frequent renter points\n”;

return result;}

C

Refactoring: step 2public public intint amountForamountFor(Rental each) {(Rental each) {

intint thisAmountthisAmount = 0;= 0;switch (each.getMovie().getPriceCode()) {

case Movie.REGULAR:CS510 S o f t w

a r e E n g i n e e r

thisAmount += 2;if (each.getDaysRented() > 2)

thisAmount+=(each.getDaysRented()-2) * 1.5;break;

case Movie.NEW_RELEASE:thisAmount += each.getDaysRented() * 3;break;

case Movie.CHILDRENS:thisAmount += 1.5;if ( h tD R t d() 3)

15

r i n g

January 20, 2008

if (each.getDaysRented() > 3)thisAmount+=(each.getDaysRented()-3) * 1.5;

break;}return return thisAmountthisAmount;;

}}

CRefactoring: step 3

TESTTESTC

S510 S o f t w a r e E

n g i n e e r

16

r i n g

January 20, 2008

Page 5: Refactoring Refactoring, applied - Purdue Universityprogram’s code is not structured in a convenient way to add it, refactor the code. C Refactoring: step 1 Write a test suite !

5

C

Refactoring: step 4oops, (double) oops, (double) --> (> (intint) bug!) bug!

public doubledouble amountFor(Rental each) {doubledouble thisAmount = 0;switch (each.getMovie().getPriceCode()) {C

S510 S o f t w a r e E

n g i n e e r

( g () g ()) {case Movie.REGULAR:

thisAmount += 2;if (each.getDaysRented() > 2)

thisAmount+=(each.getDaysRented()-2) * 1.5;break;

case Movie.NEW_RELEASE:thisAmount += each.getDaysRented() * 3;break;

case Movie.CHILDRENS:thisAmount += 1.5;if ( h tD R t d() > 3)

17

r i n g

January 20, 2008

if (each.getDaysRented() > 3)thisAmount+=(each.getDaysRented()-3) * 1.5;

break;}return thisAmount;

}

C

Refactoring: step 5Variable names not helpful

public double amountFor(Rental each) {double thisAmount = 0;switch (each.getMovie().getPriceCode()) {

CS510 S o f t w

a r e E n g i n e e r

switch (each.getMovie().getPriceCode()) {case Movie.REGULAR:

thisAmount += 2;if (each.getDaysRented() > 2)

thisAmount+=(each.getDaysRented()-2) * 1.5;break;

case Movie.NEW_RELEASE:thisAmount += each.getDaysRented() * 3;break;

case Movie.CHILDRENS:thi A t + 1 5

18

r i n g

January 20, 2008

thisAmount += 1.5;if (each.getDaysRented() > 3)

thisAmount+=(each.getDaysRented()-3) * 1.5;break;

}return thisAmount;

}

C

Refactoring: step 5public double amountFor(Rental aRentalaRental) {

double resultresult = 0;switch (aRentalaRental.getMovie().getPriceCode()) {

case Movie.REGULAR:CS510 S o f t w

a r e E n g i n e e r

resultresult += 2;if (aRentalaRental.getDaysRented() > 2)

resultresult +=(aRentalaRental.getDaysRented()-2) * 1.5;break;

case Movie.NEW_RELEASE:resultresult += aRentalaRental.getDaysRented() * 3;break;

case Movie.CHILDRENS:resultresult += 1.5;if ( R t lR t l tD R t d() 3)

19

r i n g

January 20, 2008

if (aRentalaRental.getDaysRented() > 3)resultresult +=(aRentalaRental.getDaysRented()-3) * 1.5;

break;}return resultresult ;

}

CRefactoring: step 6

Moving amount computation (does not use info from Customer only Rental)class Customer ...public double amountFor(Rental aRentalaRental) {

double resultresult = 0;CS510 S o f t w

a r e E n g i n e e r

switch (aRentalaRental.getMovie().getPriceCode()) {case Movie.REGULAR:

resultresult += 2;if (aRentalaRental.getDaysRented() > 2)

resultresult +=(aRentalaRental.getDaysRented()-2) * 1.5;break;

case Movie.NEW_RELEASE:resultresult += aRentalaRental.getDaysRented() * 3;break;

case Movie.CHILDRENS:resultresult += 1 5;

20

r i n g

January 20, 2008

resultresult += 1.5;if (aRentalaRental.getDaysRented() > 3)

resultresult +=(aRentalaRental.getDaysRented()-3) * 1.5;break;

}return resultresult ;

}

Page 6: Refactoring Refactoring, applied - Purdue Universityprogram’s code is not structured in a convenient way to add it, refactor the code. C Refactoring: step 1 Write a test suite !

6

C

Refactoring: step 6class Rental class Rental ......public double getCharge() {

double resultresult = 0;switch (getMovie().getPriceCode()) {

case Mo ie REGULAR

CS510 S o f t w

a r e E n g i n e e r

case Movie.REGULAR:resultresult += 2;

if (getDaysRented() > 2)resultresult +=(getDaysRented()-2) * 1.5;

break; case Movie.NEW_RELEASE:

resultresult += getDaysRented() * 3;break;

case Movie.CHILDRENS:

resultresult += 1.5;

21

r i n g

January 20, 2008

if (getDaysRented() > 3)

resultresult +=(getDaysRented()-3) * 1.5;break;

}return resultresult ;

}

C

Refactoring: step 6class Customer ...class Customer ...public double amountFor(Rental aRental) {

return aRental.getChargeaRental.getCharge()();;}C

S510 S o f t w a r e E

n g i n e e r

22

r i n g

January 20, 2008

C

Refactoring: step 7class Customer ...public String statement() {

double totalAmount = 0;int frequentRenterPoints = 0;Enumeration rentals = _rental.elements();String result = “Rental Record for “ + getName() + “\n”;

CS510 S o f t w

a r e E n g i n e e r

String result = Rental Record for + getName() + \n ;while (rentals.hasMoreElements()) {

double thisAmount = 0;Rental each = (Rental) rentals.nextElement();thisAmount = amountFor(each);// add frequent renter pointsfrequentRenterPoints ++;// add bonus for a two day new release rentalif ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE)&&

each.getDaysRented() > 1) frequentRenterPoints++;//show figures for this rentalresult += “\t” + each.getMovie().getTitle()+ “\t” +

String.valueOf(thisAmount) + “\n”;

23

r i n g

January 20, 2008

totalAmount += thisAmount;}// add footer linesresult += “Amount owed is “+Sting.valueOf(totalAmount) + “\n”; result += “You

earned “+Sting.valueOf(frequentRenterPoints) + “frequent renter points\n”;

return result;}

CRefactoring: step 7

class Customer ...public String statement() {

double totalAmount = 0;int frequentRenterPoints = 0;Enumeration rentals = _rental.elements();String result = “Rental Record for “ + getName() + “\n”;

CS510 S o f t w

a r e E n g i n e e r

String result = Rental Record for + getName() + \n ;while (rentals.hasMoreElements()) {

double thisAmount = 0;Rental each = (Rental) rentals.nextElement();thisAmount = each.getCharge();// add frequent renter pointsfrequentRenterPoints ++;// add bonus for a two day new release rentalif ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE)&&

each.getDaysRented() > 1) frequentRenterPoints++;//show figures for this rentalresult += “\t” + each.getMovie().getTitle()+ “\t” +

String.valueOf(thisAmount) + “\n”;

24

r i n g

January 20, 2008

totalAmount += thisAmount;}// add footer linesresult += “Amount owed is “+Sting.valueOf(totalAmount) + “\n”; result += “You

earned “+Sting.valueOf(frequentRenterPoints) + “frequent renter points\n”;

return result;}

Page 7: Refactoring Refactoring, applied - Purdue Universityprogram’s code is not structured in a convenient way to add it, refactor the code. C Refactoring: step 1 Write a test suite !

7

C

Refactoring

State of classes after moving the charge method. amountFor has been deleted.

CS510 S o f t w

a r e E n g i n e e r

*

1

25

r i n g

January 20, 2008

C

Refactoring: step 8Replace Temp with Query (thisAmount is redundant)

class Customer ...class Customer ...public String statement() {

double totalAmount = 0;int frequentRenterPoints = 0;

CS510 S o f t w

a r e E n g i n e e r

int frequentRenterPoints = 0;Enumeration rentals = _rental.elements();String result = “Rental Record for “ + getName() + “\n”;while (rentals.hasMoreElements()) {

Rental each = (Rental) rentals.nextElement();// add frequent renter pointsfrequentRenterPoints ++;// add bonus for a two day new release rentalif ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE)&&

each.getDaysRented() > 1) frequentRenterPoints++;//show figures for this rentalresult += “\t” + each.getMovie().getTitle()+ “\t” +

)) + “\n”;

26

r i n g

January 20, 2008

totalAmount += each.getCharge(); String.valueOf(each.getCharge(}// add footer linesresult += “Amount owed is “+Sting.valueOf(totalAmount) + “\n”; result += “You

earned “+Sting.valueOf(frequentRenterPoints) + “frequent renter points\n”;

return result;}

C

Refactoring: step 9Extract Method (frequent renter computation)

class Customer ...class Customer ...public String statement() {

double totalAmount = 0;int frequentRenterPoints = 0;

CS510 S o f t w

a r e E n g i n e e r

int frequentRenterPoints = 0;Enumeration rentals = _rental.elements();String result = “Rental Record for “ + getName() + “\n”;while (rentals.hasMoreElements()) {

Rental each = (Rental) rentals.nextElement();// add frequent renter points// add frequent renter pointsfrequentRenterPointsfrequentRenterPoints ++;++;// add bonus for a two day new release rental// add bonus for a two day new release rentalif ((if ((each.getMovieeach.getMovie().().getPriceCodegetPriceCode() == () == Movie.NEW_RELEASEMovie.NEW_RELEASE)&&)&&

each.getDaysRentedeach.getDaysRented() > 1) () > 1) frequentRenterPointsfrequentRenterPoints++;++;//show figures for this rentalresult += “\t” + each.getMovie().getTitle()+ “\t” +

String.valueOf(each.getCharge()) + “\n”;

27

r i n g

January 20, 2008

totalAmount += each.getCharge();}// add footer linesresult += “Amount owed is “+Sting.valueOf(totalAmount) + “\n”; result += “You

earned “+Sting.valueOf(frequentRenterPoints) + “frequent renter points\n”;

return result;}

CRefactoring: step 9

class Customer ...class Customer ...public String statement() {

double totalAmount = 0;int frequentRenterPoints = 0;Enumeration rentals = _rental.elements();C

S510 S o f t w a r e E

n g i n e e r

String result = “Rental Record for “ + getName() + “\n”;while (rentals.hasMoreElements()) {

Rental each = (Rental) rentals.nextElement();frequentRenterPointsfrequentRenterPoints += += each.getFrequentRenterPointseach.getFrequentRenterPoints();();

//show figures for this rentalresult += “\t” + each.getMovie().getTitle()+ “\t” +

String.valueOf(each.getCharge()) + “\n”;totalAmount += each.getCharge();

}// add footer linesresult + “Amount owed is “+Sting valueOf(totalAmount) + “\n”; result + “You

28

r i n g

January 20, 2008

result += “Amount owed is “+Sting.valueOf(totalAmount) + “\n”; result += “You earned “+Sting.valueOf(frequentRenterPoints)

+ “frequent renter points\n”;return result;

}

Page 8: Refactoring Refactoring, applied - Purdue Universityprogram’s code is not structured in a convenient way to add it, refactor the code. C Refactoring: step 1 Write a test suite !

8

C

Refactoring: step 9class Rental ...class Rental ...public int getFrequentRenterPoints() {

if ((if ((getMoviegetMovie().().getPriceCodegetPriceCode() == () == Movie.NEW_RELEASEMovie.NEW_RELEASE) ) && && getDaysRentedgetDaysRented() > 1) () > 1) C

S510 S o f t w a r e E

n g i n e e r

g yg yreturn 2;return 2;

else else return 1;return 1;

}}

29

r i n g

January 20, 2008

C

RefactoringClass diagram before extraction and movement of the frequent renter points calculation

*

1

CS510 S o f t w

a r e E n g i n e e r

Interaction diagram before extraction and movement of the frequent renter points calculation

1

30

r i n g

January 20, 2008

C

RefactoringClass diagram after extraction and movement of the frequent renter points calculation

*

1

CS510 S o f t w

a r e E n g i n e e r

Interaction diagram after extraction and movement of the frequent renter points calculation

1

31

r i n g

January 20, 2008

getFrequentRenterPoints()

CRefactoring: step 10

Replace Temp with Query (the temporaries make the method complex and force code duplication)

class Customer ...public String statement() {C

S510 S o f t w a r e E

n g i n e e r

double totalAmount = 0;int frequentRenterPoints = 0;Enumeration rentals = _rental.elements();String result = “Rental Record for “ + getName() + “\n”;while (rentals.hasMoreElements()) {

Rental each = (Rental) rentals.nextElement();frequentRenterPoints += each.getFrequentRenterPoints();

//show figures for this rentalresult += “\t” + each.getMovie().getTitle()+ “\t” +

String.valueOf(each.getCharge()) + “\n”;totalAmount + each getCharge();

32

r i n g

January 20, 2008

totalAmount += each.getCharge();}// add footer linesresult += “Amount owed is “+Sting.valueOf(totalAmount) + “\n”; result += “You

earned “+Sting.valueOf(frequentRenterPoints) + “frequent renter points\n”;

return result;}

Page 9: Refactoring Refactoring, applied - Purdue Universityprogram’s code is not structured in a convenient way to add it, refactor the code. C Refactoring: step 1 Write a test suite !

9

C

Refactoring: step 10class Customer ...class Customer ...public String statement() {

int frequentRenterPoints = 0;Enumeration rentals = _rental.elements();C

S510 S o f t w a r e E

n g i n e e r

String result = “Rental Record for “ + getName() + “\n”;while (rentals.hasMoreElements()) {

Rental each = (Rental) rentals.nextElement();frequentRenterPoints += each.getFrequentRenterPoints();//show figures for this rentalresult += “\t” + each.getMovie().getTitle()+ “\t” +

String.valueOf(each.getCharge()) + “\n”;}// add footer lines

lt “A t d i “ Sti l Of( tT t lChtT t lCh ()()) “\ ”

33

r i n g

January 20, 2008 33

result += “Amount owed is “+Sting.valueOf(getTotalChargegetTotalCharge()()) + “\n”;result += “You earned

“+Sting.valueOf(frequentRenterPoints)+“frequent renter points\n”;

return result;}

C

Refactoring: step 10class Customer ...class Customer ...private double getTotalCharge() {

double result = 0;Enumeration rentals = rentals.elements();C

S510 S o f t w a r e E

n g i n e e r

_while (rentals.hasMoreElements()) {

Rental each = (Rental) rentals.nextElement();result += each.getCharge();

}return result;

}

34

r i n g

January 20, 2008

C

Refactoring: step 11Replace Temp with Query

class Customer ...class Customer ...public String statement() {

int frequentRenterPoints = 0;

CS510 S o f t w

a r e E n g i n e e r

int frequentRenterPoints 0;Enumeration rentals = _rental.elements();String result = “Rental Record for “ + getName() + “\n”;while (rentals.hasMoreElements()) {

Rental each = (Rental) rentals.nextElement();frequentRenterPoints += each.getFrequentRenterPoints();//show figures for this rentalresult += “\t” + each.getMovie().getTitle()+ “\t” +

String.valueOf(each.getCharge()) + “\n”;}// dd f t li

35

r i n g

January 20, 2008

// add footer linesresult += “Amount owed is “+Sting.valueOf(getTotalCharge()) + “\n”;result += “You earned “+Sting.valueOf(frequentRenterPoints)+

“frequent renter points\n”;return result;

}

CRefactoring: step 11

Replace Temp with Queryclass Customer ...class Customer ...public String statement() {

Enumeration rentals = rental.elements();CS510 S o f t w

a r e E n g i n e e r

u e at o e ta s _ e ta .e e e ts();String result = “Rental Record for “ + getName() + “\n”;while (rentals.hasMoreElements()) {

Rental each = (Rental) rentals.nextElement();//show figures for this rentalresult += “\t” + each.getMovie().getTitle()+ “\t” +

String.valueOf(each.getCharge()) + “\n”;}// add footer linesresult += “Amount owed is “+Sting.valueOf(getTotalCharge()) + “\n”;

36

r i n g

January 20, 2008

g (g g ())

result += “You earned “+Sting.valueOf(getFrequentRenterPointsgetFrequentRenterPoints()())+“frequent renter points\n”;

return result;}

Page 10: Refactoring Refactoring, applied - Purdue Universityprogram’s code is not structured in a convenient way to add it, refactor the code. C Refactoring: step 1 Write a test suite !

10

C

Refactoring: step 11class Customer ...class Customer ...

private double getFrequentRenterPoints() {double result = 0;Enumeration rentals = rentals.elements();C

S510 S o f t w a r e E

n g i n e e r

_while (rentals.hasMoreElements()) {

Rental each = (Rental) rentals.nextElement();result += each.getFrequentRenterPoints();

}return result;

}

37

r i n g

January 20, 2008

C

RefactoringClass diagram before extraction of the totals

*

1

CS510 S o f t w

a r e E n g i n e e r

Interaction diagram before extraction of the totals

1

38

r i n g

January 20, 2008

getFrequentRenterPoints()

C

RefactoringClass diagram after extraction of the totals

*

1

CS510 S o f t w

a r e E n g i n e e r

Interaction diagram after extraction of the totals

1

39

r i n g

January 20, 2008

CRefactoring

RemarksMost refactoring reduce code size, but this is not necessarily the case The point is to make code easier to modify and more

CS510 S o f t w

a r e E n g i n e e r

the case. The point is to make code easier to modify and more readable.Performance gets a hit by running the same loop three times, or does it? Profile the program and find the answer.

40

r i n g

January 20, 2008

Page 11: Refactoring Refactoring, applied - Purdue Universityprogram’s code is not structured in a convenient way to add it, refactor the code. C Refactoring: step 1 Write a test suite !

11

C

Software extensionThe requested method can be added with minimal code duplication

l C t

CS510 S o f t w

a r e E n g i n e e r

class Customer ...public String htmlStatement() {

Enumeration rentals = _rental.elements();String result = “<H1>Rental Record for<EM> “ + getName() + “<EM></H1><P>\n”;while (rentals.hasMoreElements()) {

Rental each = (Rental) rentals.nextElement();//show figures for this rentalresult += each.getMovie().getTitle()+ “: ” +

String.valueOf(each.getCharge()) + “<BR>\n”;}// add footer lines

41

r i n g

January 20, 2008

// add footer linesresult += “<P>Amount owed is<EM> “+Sting.valueOf(getTotalCharge()) +

“</EM><P>\n”; result += “You earned <EM>“+Sting.valueOf(getFrequentRenterPointsgetFrequentRenterPoints()())+

“</EM> frequent renter points<P>\n”;return result;

}

C

New functionality

Getting ready to change the classification of the movies in the store. P h l f h d f

CS510 S o f t w

a r e E n g i n e e r

Perhaps new classification, perhaps modification to existing.Charging and frequent renting will be affected.

42

r i n g

January 20, 2008

C

Refactoring: step 12Replacing conditional logic on Price Code with polymorphism

CS510 S o f t w

a r e E n g i n e e r

43

r i n g

January 20, 2008

CRefactoring: step 12

Move getChargeclass Rental ...class Rental ...public double getCharge() {

double result = 0;CS510 S o f t w

a r e E n g i n e e r

switch (getMovie().getPriceCode()) {case Movie.REGULAR:

result += 2;if (getDaysRented() > 2)

result +=(getDaysRented()-2) * 1.5;break;

case Movie.NEW_RELEASE:result += getDaysRented() * 3;break;

case Movie.CHILDRENS:result += 1 5;

44

r i n g

January 20, 2008

result += 1.5;if (getDaysRented() > 3)

result +=(getDaysRented()-3) * 1.5;break;

}return result ;

}

Page 12: Refactoring Refactoring, applied - Purdue Universityprogram’s code is not structured in a convenient way to add it, refactor the code. C Refactoring: step 1 Write a test suite !

12

C

Refactoring: step 12class Movie ...class Movie ...public double getCharge(int daysRented) {

double result = 0;switch (getPriceCode()) {

case REGULAR

CS510 S o f t w

a r e E n g i n e e r

case REGULAR:result += 2;if (daysRented > 2)

result +=(daysRented-2) * 1.5;break;

case NEW_RELEASE:result += daysRented * 3;break;

case CHILDRENS:result += 1.5;

45

r i n g

January 20, 2008

if (daysRented > 3)result +=(daysRented-3) * 1.5;

break;}return result ;

}

C

Refactoring: step 12class Rental ...class Rental ...public double getCharge() {

return _movie.getCharge(_daysRented);}C

S510 S o f t w a r e E

n g i n e e r

46

r i n g

January 20, 2008

C

Refactoring: step 13Move getFrequentRenterPoints()

class Rental ...class Rental ...public int getFrequentRenterPoints() {

CS510 S o f t w

a r e E n g i n e e r

public int getFrequentRenterPoints() {if ((getMovie().getPriceCode() == Movie.NEW_RELEASE)&& getDaysRented() > 1)

return 2;else

return 1;}

47

r i n g

January 20, 2008

CRefactoring: step 13

class Movie ...public int getFrequentRenterPointsgetFrequentRenterPoints((intint daysRenteddaysRented) ) {

if ((getPriceCode() == Movie.NEW_RELEASE) && daysRented > 1) return 2;C

S510 S o f t w a r e E

n g i n e e r

else return 1;

}

class Rental ...public int getFrequentRenterPoints() {

return _movie.getFrequentRenterPoints(_daysRented);

48

r i n g

January 20, 2008

}

Page 13: Refactoring Refactoring, applied - Purdue Universityprogram’s code is not structured in a convenient way to add it, refactor the code. C Refactoring: step 1 Write a test suite !

13

C

Refactoring

Class diagram before moving methods to movie

CS510 S o f t w

a r e E n g i n e e r

Class diagram after moving methods to movie

*

1

49

r i n g

January 20, 2008

*

1

C

Refactoring

Inheritance

CS510 S o f t w

a r e E n g i n e e r

50

r i n g

January 20, 2008

C

RefactoringInheritance

CS510 S o f t w

a r e E n g i n e e r

51

r i n g

January 20, 2008

CRefactoring: step 14

Replace Type Code with State/StrategyC

S510 S o f t w a r e E

n g i n e e r

class Movie ...class Movie ...public Movie(String name, int priceCode) {

_name = name;_priceCode = priceCode;

}

52

r i n g

January 20, 2008

Page 14: Refactoring Refactoring, applied - Purdue Universityprogram’s code is not structured in a convenient way to add it, refactor the code. C Refactoring: step 1 Write a test suite !

14

C

Refactoring: step 14

class Movie ...class Movie ...public Movie(String name, int priceCode) {

_name = name;CS510 S o f t w

a r e E n g i n e e r

setPriceCode(priceCode);setPriceCode(priceCode);}

53

r i n g

January 20, 2008 53

C

Refactoring: step 14abstract class Price {

abstract int getPriceCode();}

CS510 S o f t w

a r e E n g i n e e r

class ChildrenPrice extends Price {int getPriceCode(){

return MOVIE.CHILDREN;}

}class NewReleasePrice extends Price {

int getPriceCode(){return MOVIE.NEW_RELEASE;

}}

54

r i n g

January 20, 2008

}class RegularPrice extends Price {

int getPriceCode(){return MOVIE.REGULAR;

}}

C

Refactoring: step 15class Movie ...class Movie ...

public int getPriceCode() {return priceCode;C

S510 S o f t w a r e E

n g i n e e r

_p}public void setPriceCode(int arg) {

_priceCode = arg;}private int _priceCode;

55

r i n g

January 20, 2008

CRefactoring: step 15

class Movie ...class Movie ...public int getPriceCode() {

return _return _price.getPriceCodeprice.getPriceCode;;}p blic oid setPriceCode(int arg) {

CS510 S o f t w

a r e E n g i n e e r

public void setPriceCode(int arg) {switch (switch (argarg) {) {

case REGULAR:case REGULAR:_price = new _price = new RegularPriceRegularPrice();();break;break;

case CHILDREN:case CHILDREN:_price = new _price = new ChildrenPriceChildrenPrice();();break;break;

case NEW_RELEASE:case NEW_RELEASE:_price = new _price = new NewReleasePriceNewReleasePrice();();

56

r i n g

January 20, 2008

break;break;default: default: throw new throw new IllegalArgumentExceptionIllegalArgumentException(“Incorrect Price Code”);(“Incorrect Price Code”);

}}}private Price _price;private Price _price;

Page 15: Refactoring Refactoring, applied - Purdue Universityprogram’s code is not structured in a convenient way to add it, refactor the code. C Refactoring: step 1 Write a test suite !

15

C

Refactoring: step 16Move Method

class Movie ...class Movie ...public double getCharge(int daysRented) {

double result = 0;CS510 S o f t w

a r e E n g i n e e r

switch (getPriceCode()) {case REGULAR:

result += 2;if (getDaysRented() > 2)

result +=(getDaysRented()-2) * 1.5;break;

case NEW_RELEASE:result += getDaysRented() * 3;break;

case CHILDRENS:result += 1 5;

57

r i n g

January 20, 2008

result + 1.5;if (getDaysRented() > 3)

result +=(getDaysRented()-3) * 1.5;break;

}return result ;

}

C

Refactoring: step 16class Movie ...class Movie ...public double getCharge(int daysRented) {

return __price.getChargeprice.getCharge((daysRenteddaysRented));}C

S510 S o f t w a r e E

n g i n e e r

58

r i n g

January 20, 2008

C

Refactoring: step 16Replace Conditional with Polymorphism

class Price ...class Price ...double getCharge(int daysRented) {

double result = 0;CS510 S o f t w

a r e E n g i n e e r

switch (getPriceCode()) {case MOVIE.REGULAR:

result += 2;if (getDaysRented() > 2)

result +=(getDaysRented()-2) * 1.5;break;

case MOVIE.NEW_RELEASE:result += getDaysRented() * 3;break;

case MOVIE.CHILDRENS:result += 1 5;

59

r i n g

January 20, 2008

result += 1.5;if (getDaysRented() > 3)

result +=(getDaysRented()-3) * 1.5;break;

}return result ;

}

CRefactoring: step 16

class RegularPrice ...class RegularPrice ...double getCharge(int daysRented) {

double result = 2;if (getDaysRented() > 2)res lt + (getDa sRented() 2) * 1 5

CS510 S o f t w

a r e E n g i n e e r

result +=(getDaysRented()-2) * 1.5;return result;

}class NewReleasePrice ...class NewReleasePrice ...double getCharge(int daysRented) {

return daysRented * 3;}class ChildrenPrice ...class ChildrenPrice ...double getCharge(int daysRented) {

double result = 1.5;

60

r i n g

January 20, 2008

if (getDaysRented() > 3)result +=(getDaysRented()-3) * 1.5;

return result ;}class Price...class Price...

abstract double getCharge(int daysRented);

Page 16: Refactoring Refactoring, applied - Purdue Universityprogram’s code is not structured in a convenient way to add it, refactor the code. C Refactoring: step 1 Write a test suite !

16

C

Refactoring: step 17Replace Conditional with Polymorphism

class Rental ...class Rental ...int getFrequentRenterPoints(int daysRented) {

CS510 S o f t w

a r e E n g i n e e r

int getFrequentRenterPoints(int daysRented) {if ((getPriceCode() == Movie.NEW_RELEASE) && daysRented > 1)

return 2;else

return 1;}

61

r i n g

January 20, 2008

C

Refactoring: step 17class Movie ...class Movie ...int getFrequentRenterPoints(int daysRented) {

return _price.getFrequentRenterPoints(daysRented);}C

S510 S o f t w a r e E

n g i n e e r

class Price...class Price...int getFrequentRenterPoints(int daysRented) {

return 1;}

class class NewReleasePriceNewReleasePrice....int getFrequentRenterPoints(int daysRented) {

return (daysRented > 1) ? 2:1;

62

r i n g

January 20, 2008

}

C

Refactoring Principles

Why do we Why do we refactorrefactor??To improve the design of softwareTo make software easier to understandC

S510 S o f t w a r e E

n g i n e e r

To help you find bugsTo make you program faster

When should we When should we refactorrefactor??1. Refactor when you add functionality2. Refactor when you need to fix a bug3. Refactor as you do code reviews– Refactor when the code starts to smell.

What about performance?What about performance?

63

r i n g

January 20, 2008

What about performance?What about performance?Worry about performance only when you have identified a performance problem

CBad Smells in Code

If it stinks, change it.--Grandma Beck on child rearing

CS510 S o f t w

a r e E n g i n e e r

Duplicated Code (stench 10)

If the same code structure is repeated

Extract Method- gather duplicated codePull Up Field - move to a common parentF T l t M th d th si il ts l i h l s

64

r i n g

January 20, 2008

Form Template Method - gather similar parts, leaving holesSubstitute Algorithm - choose the clearer algorithmExtract class - for unrelated classes, create a new class with functionality

Page 17: Refactoring Refactoring, applied - Purdue Universityprogram’s code is not structured in a convenient way to add it, refactor the code. C Refactoring: step 1 Write a test suite !

17

C

Bad Smells in Code

Long Method(stench 7)

CS510 S o f t w

a r e E n g i n e e r

If the body of a method is over a page (choose your page size)

Extract Method- extract related behaviorReplace Temp with Query - remove temporaries when they obscure meaningIntroduce Parameter Object - slim down parameter lists by

ki h i bj

65

r i n g

January 20, 2008

making them into objectsReplace Method with Method Object - still too many parametersDecompose Conditionals - conditional and loops can be moved to their own methods

C

Bad Smells in Code

Large Class (stench 7)

If l h ith t i bl t th d

CS510 S o f t w

a r e E n g i n e e r

If a class has either too many variables or too many methods

Extract Class - to bundle variables/methods

66

r i n g

January 20, 2008

C

Bad Smells in Code

Divergent Change (stench 5)

If fi d lf t dl h i th l th

CS510 S o f t w

a r e E n g i n e e r

If you find yourself repeatedly changing the same class thenthere is probably something wrong with it

Extract Class - group functionality commonly changed into a class

67

r i n g

January 20, 2008

CBad Smells in Code

Shotgun Surgery (stench 5)

If fi d lf ki l t f ll h f h

CS510 S o f t w

a r e E n g i n e e r

If you find yourself making a lot of small changes for each desired

change

Move Method/Field - pull all the changes into a single classInline Class - group a bunch of behaviors together

68

r i n g

January 20, 2008

Page 18: Refactoring Refactoring, applied - Purdue Universityprogram’s code is not structured in a convenient way to add it, refactor the code. C Refactoring: step 1 Write a test suite !

18

C

Bad Smells in Code

Feature Envy(stench 6)

CS510 S o f t w

a r e E n g i n e e r

If a method seems more interested in a class other than the class it

actually is in

Move Method - move the method to the desired classExtract Method - if only part of the method shows the

69

r i n g

January 20, 2008

symptoms

C

Bad Smells in Code

Data Clumps (stench 4)

D t it th t f tl t th i th d i t

CS510 S o f t w

a r e E n g i n e e r

Data items that are frequently together in method signatures and

classes belong to a class of their own

Extract Class - turn related fields into a classIntroduce Parameter Object - for method signatures

70

r i n g

January 20, 2008

C

Bad Smells in Code

Primitive Obsession (stench 3)

CS510 S o f t w

a r e E n g i n e e r

Primitive types inhibit change

Replace Data Value with Object - on individual data valuesMove Method/Field - pull all the changes into a single classIntroduce Parameter Object - for signaturesReplace Array with Object - to get rid of arrays

71

r i n g

January 20, 2008

CBad Smells in Code

Switch Statements(stench 5)

CS510 S o f t w

a r e E n g i n e e r

Switch statements lead to duplication and inhibit change

Extract method - to remove the switchMove method - to get the method where polymorphism can applyReplace Type Code with State/Strategy - set up inheritance

72

r i n g

January 20, 2008

Replace Conditional with Polymorphism - get rid of the switch

Page 19: Refactoring Refactoring, applied - Purdue Universityprogram’s code is not structured in a convenient way to add it, refactor the code. C Refactoring: step 1 Write a test suite !

19

C

Bad Smells in Code

Parallel Inheritance Hierarchies (stench 6)

If h k b l i f th hi h

CS510 S o f t w

a r e E n g i n e e r

If when ever you make a subclass in one corner of the hierarchy, you must create another subclass in another corner

Move Method/Field - get one hierarchy to refer to the other

73

r i n g

January 20, 2008

C

Bad Smells in Code

Lazy Class (stench 4)

If l ( ft f t i ) d t d h li i t it

CS510 S o f t w

a r e E n g i n e e r

If a class (e.g. after refactoring) does not do much, eliminate it.

Collapse Hierarchy- for subclassesInline Class - remove a single class

74

r i n g

January 20, 2008

C

Bad Smells in Code

Speculative Generality(stench 4)

CS510 S o f t w

a r e E n g i n e e r

If a class has features that are only used in test cases, remove them.

Collapse Hierarchy- for useless abstract classesInline Class - for useless delegationRename Method - methods with odd abstract names should be b h d h

75

r i n g

January 20, 2008

brought down to earth

CBad Smells in Code

Temporary Field (stench 3)

If l h fi ld th t l t i i l t t

CS510 S o f t w

a r e E n g i n e e r

If a class has fields that are only set in special cases, extract them

Extract Class- for the special fields

76

r i n g

January 20, 2008

Page 20: Refactoring Refactoring, applied - Purdue Universityprogram’s code is not structured in a convenient way to add it, refactor the code. C Refactoring: step 1 Write a test suite !

20

C

Bad Smells in Code

Message Chains (stench 3)

L h i f t t t l b ittl

CS510 S o f t w

a r e E n g i n e e r

Long chains of messages to get to a value are brittle as any change

in the intermittent structure will break the code

Hide Delegate - remove one link in a chainExtract Method - change the behavior to avoid chains

77

r i n g

January 20, 2008

C

Bad Smells in Code

Middle Man (stench 3)

A i t di bj t i d t ft t t t

CS510 S o f t w

a r e E n g i n e e r

An intermediary object is used too often to get at encapsulated values

Remove Middle Man - to talk directly to the targetReplace Delegation with Inheritance - turns the middle man into a subclass of the real object

78

r i n g

January 20, 2008

C

Bad Smells in Code

Inappropriate Intimacy (stench 5)

Cl t i ti t d d t h ti d l i i

CS510 S o f t w

a r e E n g i n e e r

Classes are too intimate and spend too much time delving in each other’s private parts

Move Method/Field - to separate pieces in order to reduce intimacyExtract Class - make a common class of shared behavior/dataReplace Inheritance with Delegation - when a subclass is

79

r i n g

January 20, 2008

Replace Inheritance with Delegation when a subclass is getting too cozy

CBad Smells in Code

Comments (stench 2)

C t ft i f l d id

CS510 S o f t w

a r e E n g i n e e r

Comments are often a sign of unclear code... consider refactoring

80

r i n g

January 20, 2008