Presentation is loading. Please wait.

Presentation is loading. Please wait.

Refactoring Improving code after it has been written.

Similar presentations


Presentation on theme: "Refactoring Improving code after it has been written."— Presentation transcript:

1 Refactoring Improving code after it has been written

2 The Problem: Design is not always optimal “Improving the design after it has been written” “Improving the design after it has been written” Code deteriorates over time with changes Code deteriorates over time with changes Make many small changes Make many small changes Test after each change Test after each change Radical change through cumulative effect Radical change through cumulative effect

3 An Example Write Software for Movie Rentals

4 The class Movie public class Movie{ public static final int CHILDRENS = 2; public static final int REGULAR = 0; public static final int NEW_RELEASE = 1; private String _title; private int _priceCode; public Movie(String title, int priceCode){ _title = title; _priceCode = priceCode;} public int getPriceCode(){return _priceCode;} public void setPriceCode(int arg){ _priceCode = arg;} public String getTitle(){return _title;} }

5 The class Rental public class Rental{ private Movie –movie; public Rental(Movie movie, int daysRented){ _movie = movie; _daysRented = daysRented;} public int getDaysRented(){return _daysRented;} public Movie getMovie(){return _movie;} }

6 The class Customer public class Customer{ private String _name; private Vector _rentals = new Vector(); public Customer (String name){_name = name;} public void addRental(Rental arg){ _rentals.addElement(arg);} public String getName(){return _name;} public void statement(); //see below }

7 Class Diagram of Rental Program Customer Rental Movie statement() int: daysRented int: priceCode 1 * 1 *

8 Sequence Diagram

9 Method statement (1 of 3) public String statement(){ double totalAmount = 0; int frequentRenterPoints = 0; Enumeration rentals = _rentals.elements(); String result = “Rental Record for”+getname()+”\n”; while(rentals.hasMoreElements()){ double thisAmount = 0; Rental each = (Rental)rentals.nextElement();

10 Method statement (2 of 3) 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: thisAmount += 1.5; if (each.getDaysRented()>3) thisAmount += (each.getDaysRented()-3)*1.5; break; } //switch

11 Method statement (3 of 3) frequentRenterPoints++; if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) &&(each.getDaysRented()>1) frequentRenterPoints++; result += “\t”+each.getMovie().getTitle()+”\t”+ String.valueOf(thisAmount)+”\n”; totalAmount += thisAmount; result += “AmountOwed is “ + String.valueOf(totalAmount) +”\n”; result += “You earned “ + String.valueOf( frequentRenterPoints)+”frequent renter points”; return result; }

12 What is wrong? Program works Program works Method statement is way too long Method statement is way too long Decompose it into smaller pieces Decompose it into smaller pieces So find a logical piece of code So find a logical piece of code Try the switch statement Try the switch statement

13 Write method amountFor(Rental each); private int amountFor(Rental each){ int thisAmount = 0; switch (each.getMovie().getPriceCode()){ case Movie.REGULAR: thisAmount += 2; if (each.getDaysRented()>2) thisAmount += (each.getDaysRented()-2)*1.5; break; case Movie.NEWRELEASE: thisAmount += each.getDaysRented()*3; break; case Movie.CHILDRENS: thisAmount += 1.5; if (each.getDaysRented()-3)*1.5; break;} return thisamount; } //switch MoveMethod

14 public String statement(){ double totalAmount = 0; int frequentRenterPoints = 0; Enumeration rentals = _rentals.elements(); String result = “Rental Record for”+getname()+”\n”; while(rentals.hasMoreElements()){ double thisAmount = 0; Rental each = (Rental)rentals.nextElement(); thisAmount = amountFor(each); frequentRenterPoints++; if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) &&(each.getDaysRented()>1) frequentRenterPoints++; result += “\t”+each.getMovie().getTitle()+”\t”+ String.valueOf(thisAmount)+”\n”; totalAmount += thisAmount; result += “AmountOwed is “ + String.valueOf(totalAmount) +”\n”; result += “You earned “ + String.valueOf( frequentRenterPoints)+”frequent renter points”; return result; }

15 Problem Tests reveal that return type is double, not int

16 Write it again private double amountFor(Rental aRental){ double result = 0; switch (aRental.getMovie().getPriceCode()){ case Movie.REGULAR: result += 2; if (aRental.getDaysRented()>2) result += (each.getDaysRented()-2)*1.5; break; case Movie.NEWRELEASE: result += aRental.getDaysRented()*3; break; case Movie.CHILDRENS: result += 1.5; if (aRental.getDaysRented()-3)*1.5; break; } return result; } //switch

17 Mistake was found Testing is crucial at each refactoring step

18 Examine new amountFor() It doesn’t use any customer data! It doesn’t use any customer data! Method is in the wrong place. Method is in the wrong place. Put it in rental Put it in rental It gets a new name: getCharge() It gets a new name: getCharge()

19 class Rental … public double getCharge() { double result = 0; switch (getMovie().getPriceCode()){ case Movie.REGULAR: result += 2; if (getDaysRented()>2) result += (getDaysRented()-2)*1.5; break; case Movie.NEWRELEASE: result += getDaysRented()*3; break; case Movie.CHILDRENS: result += 1.5; if (getDaysRented()-3)*1.5; break; } return result; } MoveMethod

20 class Customer… Private double amountFor(Rental aRental){ return aRental.getCharge(); }

21 Fix up program Have to find all references for amountFor and change to getCharge()

22 class customer… public String statement(){ double totalAmount = 0; int frequentRenterPoints = 0; Enumeration rentals = _rentals.elements(); String result = “Rental Record for”+getname()+”\n”; while(rentals.hasMoreElements(){ double thisAmount = 0; Rental each = (Rental)rentals.nextElement(); thisAmount = amountFor(each); frequentRenterPoints++; if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) &&(each.getDaysRented()>1) frequentRenterPoints++; result += “\t”+each.getMovie().getTitle()+”\t”+ String.valueOf(thisAmount)+”\n”; totalAmount += thisAmount;} result += “AmountOwed is “ + String.valueOf(totalAmount) +”\n”; result += “You earned “ + String.valueOf( frequentRenterPoints)+”frequent renter points”; return result; }

23 becomes

24 class customer… public String statement(){ double totalAmount = 0; int frequentRenterPoints = 0; Enumeration rentals = _rentals.elements(); String result = “Rental Record for”+getname()+”\n”; while(rentals.hasMoreElements(){ double thisAmount = 0; Rental each = (Rental)rentals.nextElement(); thisAmount = each.getCharge(); frequentRenterPoints++; if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) &&(each.getDaysRented()>1) frequentRenterPoints++; result += “\t”+each.getMovie().getTitle()+”\t”+ String.valueOf(thisAmount)+”\n”; totalAmount += thisAmount;} result += “AmountOwed is “ + String.valueOf(totalAmount) +”\n”; result += “You earned “ + String.valueOf( frequentRenterPoints)+”frequent renter points”; return result; }

25 Now notice thisAmount is redundant

26 class customer… public String statement(){ double totalAmount = 0; int frequentRenterPoints = 0; Enumeration rentals = _rentals.elements(); String result = “Rental Record for”+getname()+”\n”; while(rentals.hasMoreElements(){ double thisAmount = 0; Rental each = (Rental)rentals.nextElement(); frequentRenterPoints++; if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) &&(each.getDaysRented()>1) frequentRenterPoints++; result += “\t”+each.getMovie().getTitle()+”\t”+ String.valueOf(each.getCharge())+”\n”; totalAmount += each.getCharge();} result += “AmountOwed is “ + String.valueOf(totalAmount) +”\n”; result += “You earned “ + String.valueOf( frequentRenterPoints)+”frequent renter points”; return result; } Replace Temp with Query

27 Now extract code for Frequent Renter Points

28 public String statement(){ double totalAmount = 0; int frequentRenterPoints = 0; Enumeration rentals = _rentals.elements(); String result = “Rental Record for”+getname()+”\n”; while(rentals.hasMoreElements(){ Rental each = (Rental)rentals.nextElement(); frequentRenterPoints++; if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) &&(each.getDaysRented()>1) frequentRenterPoints++; result += “\t”+each.getMovie().getTitle()+”\t”+ String.valueOf(each.getCharge())+”\n”; totalAmount += each.getCharge();} result += “AmountOwed is “ + String.valueOf(totalAmount) +”\n”; result += “You earned “ + String.valueOf( frequentRenterPoints)+”frequent renter points”; return result; } Extract Method

29 And put in in Rental:

30 class Customer… public String statement(){ double totalAmount = 0; int frequentRenterPoints = 0; Enumeration rentals = _rentals.elements(); String result = “Rental Record for”+getname()+”\n”; while(rentals.hasMoreElements(){ double thisAmount = 0; Rental each = (Rental)rentals.nextElement(); frequentRenterPoints += each.getFrequentRenterPoints(); result += “\t”+each.getMovie().getTitle()+”\t”+ String.valueOf(each.getCharge())+”\n”; totalAmount += each.getCharge();} result += “AmountOwed is “ + String.valueOf(totalAmount) +”\n”; result += “You earned “ + String.valueOf( frequentRenterPoints)+”frequent renter points”; return result; }

31 class Rental… int getFrequentRenterPoints(){ if ((getMovie().getPriceCode() == Movie.NEW_RELEASE) &&(getDaysRented()>1) return 2; else return 1; }

32 RemoveTemp Variables Temps encourage complexity Temps encourage complexity Here: totalAmount and frequentRenterPoints Here: totalAmount and frequentRenterPoints Replace totalAmount with Customer method getTotalCharge() Replace totalAmount with Customer method getTotalCharge()

33 class Customer… public String statement(){ int frequentRenterPoints = 0; Enumeration rentals = _rentals.elements(); String result = “Rental Record for”+getname()+”\n”; while(rentals.hasMoreElements(){ Rental each = (Rental)rentals.nextElement(); frequentRenterPoints += each.getFrequentRenterPoints(); result += “\t”+each.getMovie().getTitle()+”\t”+ String.valueOf(each.getCharge())+”\n”; totalAmount += each.getCharge();} result += “AmountOwed is “ + String.valueOf(getTotalCharge()) +”\n”; result += “You earned “ + String.valueOf( frequentRenterPoints)+”frequent renter points”; return result; } Replace Temp with Query

34 class customer… private double getTotalCharge(){ double result = 0; Enumeration rentals = _rentals.elements(); while (rentals.hasMoreElements()){ Rental each = (Rental)rentals.nextElement(); result += each.getCharge(); } return result; }

35 Now do the same for frequentRenterPoints


Download ppt "Refactoring Improving code after it has been written."

Similar presentations


Ads by Google