SE 333/433 Software Testing & Quality Assurance
Refactoring
1
Last Week
2
Another System Model (Data-Bases)
Program (in Java)
Model transformation
Refactoring
System Model (in UML)
Reverse engineering
Another Program (Java)
Model space
Source code space
3
Forward engineering
• Design to code • Refactoring
4
Class and Attribute
float
float
5
float float
float float
Operations
6
Visibility
7
Class scope
8
Unidirectional Association
11
Advertiser Account
public class Advertiser { private Account account;
} }
public Advertiser() {
account = new Account();
}
public Account getAccount() {
return account;
9
Association names & role defaults
10
public class Advertiser { /* account is initialized
public class Account {
/* owner is initialized
} }
private Account account; public Advertiser() {
* never modified. */
private Advertiser owner;
public Account(owner:Advertiser) {
Bi‐directional Association
Advertiser
Account
* in the constructor and never
* modified. */
* in the constructor and
account = new Account(this);
this.owner = owner; }
}
public Account getAccount() {
public Advertiser getOwner() { return owner;
return account;
} }
11
11
Multiplicity
12
Aggregation and Composition
13
Generalization
14
Realization
15
Abstraction
16
Association classes
17
Associations, Visibility & Scope
18
?
public int getX() { return _x;
}
Example
public class Point { private int _x; private int _y;
public class Polygon { private Point corners[];
}
public Point(int x, int y) { _x=x; _y=y;
}
public int getY() { return _y;
}
Polygon(int[][] points) { }
19
Polygon(int[][] points)
throws IllegalArgumentException {
if (points.length< 3) {
throw new IllegalArgumentException( "Not enough corners ");
}
}
else {
corners=new Point[points.length]; for (int i=0; i
class PizzaDelivery {
// …
int getRating() {
return numberOfLateDeliveries > 5 ? 2 : 1;
Inline Method
• When a method body is more obvious than the method itself.
• Eliminates code smell : Dead code (unused class, method, field etc.
class PizzaDelivery
28
• Eliminates code smell : comments
void renderBanner() {
if ((platform.toUpperCase().indexOf(“MAC”) > ‐1) && (browser.toUpperCase().indexOf(“IE”) > ‐1)
&& wasInitialized() && resize > 0 ) { // do something } }
Extract Variable
void renderBanner() {
final boolean isMacOs = platform.toUpperCase().indexOf(“MAC”) > ‐1;
final boolean isIE = browser.toUpperCase().indexOf(“IE”) > ‐1; final boolean wasResized = resize > 0;
if (isMacOs && isIE && wasInitialized() && wasResized) { // do something }
}
29
double basePrice = order.basePrice(); return basePrice > 1000;
}
Inline Temp
• You have a temporary variable that’s assigned the result of a simple expression and nothing more.
boolean hasDiscount(Order order) {
boolean hasDiscount(Order order) { return order.basePrice() > 1000;
}
30
if (basePrice > 1000) { return basePrice * 0.95; }
} else {
else {
return basePrice * 0.98;
return basePrice() * 0.98; }
} }
}
double basePrice() {
Replace Temp with Query
• If a temporary variable hold the result of an expression.
• Extract the expression into a method.
• Eliminates code smell : Long method, duplicate code
double calculateTotal() {
double calculateTotal() {
double basePrice = quantity * itemPrice;
if (basePrice() > 1000) { return basePrice() * 0.95;
return quantity * itemPrice; } 31
• Inline Class
Refactoring Techniques
• Moving Features between Objects • Move Method
• Move Field
• Extract Class
32
Move Method
• If a method on one class uses (or is used by) another class more than the class on which its defined, move it to the other class.
• Eliminates code smell : Shotgun Surgery, Feature Envy, Data Class
public class Student
{
public boolean isTaking(Course course)
{
return (course.getStudents().contains(this));
}
}
public class Course
{ public boolean isTaking(Student student) private List students;
public List getStudents()
{
return students;
}
}
public class Student {
}
public class Course {
private List students;
{
return students.contains(student); }
}
33
Move Method
34
Move Field
35
public class Customer
{
private String name;
private String workPhoneAreaCode; private String workPhoneNumber;
public class Customer
{
private String name; private Phone workPhone; }
}
public class Phone
{
private String areaCode; private String number;
Extract Class
• Break one class into two, e.g. Having the phone details as part of the Customer class is not a realistic OO model.
• Eliminate code smell : Large Class, Duplicate Code, ..
}
36
Extract Class
37
Inline Class
• Eliminate code smell : Shotgun Surgery, lazy class, oldbagage/deadcode ..
38
Refactoring Techniques
• Generalization
• Pull Up Field
• Pull Up Method
• Push Down Method
• Push Down Field
• Extract Subclass
• Extract Superclass
• Replace Inheritance with Delegation • Replace Delegation with Inheritance
39
• Eliminate code smell : Duplicate Code
Pull Up Field
40
• Eliminate code smell : Duplicate Code
Pull Up Method
41
Push Down Method
42
Push Down Field
43
Extract Subclass
• When a class has features (attributes and methods) that would only be useful in specialized instances, we can create a specialization of that class and give it those features.
• This makes the original class less specialized (i.e., more abstract), and good design is about binding to abstractions wherever possible.
44
• Eliminate code smell : Large Class
public class Person{
public class Person
{
protected String name; }
private String name;
private String jobTitle; }{
Extract Subclass
public class Employee extends Person
private String jobTitle; }
45
Extract Subclass
46
Extract Superclass
• When you find two or more classes that share common features, consider abstracting those shared features into a super‐class.
• This makes it easier to bind clients to an abstraction, and removes duplicate code from the original classes.
47
private String name; private Course course; }
public class Student extends Person {
private Course course;
}
Extract Superclass
public class Employee
{
private String name;
private String jobTitle; }{
public class Student private String jobTitle; {}
public abstract class Person {
protected String name;
}
public class Employee extends Person
48
• Eliminate code smell : Duplicate Code
Extract Superclass
49
Replace Inheritance with Delegation
50
Replace Delegation with Inheritance
51
Refactoring Techniques
• Simplifying Conditional Expressions
• Decompose Conditional
• Consolidate Conditional Expression
• Replace Nested Conditional with Guard Clauses • Replace Conditional with Polymorphism
52
• Eliminates : long method
} else {
charge = quantity * summerRate;
}
else {
}
charge = winterCharge(quantity); }
Decompose Conditional
if (date.before(SUMMER_START) || date.after(SUMMER_END)) { charge = quantity * winterRate + winterServiceCharge;
if (isSummer(date)) {
charge = summerCharge(quantity);
53
double disabilityAmount() { if (seniority < 2) {
double disabilityAmount() {
if (isNotEligableForDisability()) {
return 0; }
return 0; }
if (monthsDisabled > 12) { return 0; }
if (isPartTime) { return 0;
}
// Compute the disability amount. // … }
// Compute the disability amount. // …
}
Consolidate Conditional Expression
• Eliminates : Duplicate Code
54
public double getPayAmount() { double result;
if (isDead){
result = deadAmount(); }
else {
if (isSeparated){
public double getPayAmount() { if (isDead){
result = separatedAmount(); } else {
if (isSeparated){
return separatedAmount(); }
if (isRetired){
return retiredAmount();
}
return normalPayAmount(); }
if (isRetired){
result = retiredAmount(); }
else{
result = normalPayAmount();
}
55
}
}
}
return result;
Replace Nested Conditional with Guard Clauses
return deadAmount(); }
class Bird { // …
class European extends Bird { double getSpeed() {
return getBaseSpeed();
double getSpeed() { switch (type) {
} }
Replace Conditional with Polymorphism
• Eliminates : Switch Statment
abstract class Bird { // …
case EUROPEAN: return getBaseSpeed();
case AFRICAN: return getBaseSpeed() ‐ getLoadFactor() * numberOfCoconuts;
case NORWEGIAN_BLUE:
return (isNailed) ? 0 : getBaseSpeed(voltage);
}
class African extends Bird { double getSpeed() {
throw new RuntimeException(“Should be unreachable”); }
}
class NorwegianBlue extends Bird { double getSpeed() {
}
return (isNailed) ? 0 : getBaseSpeed(voltage); }
abstract double getSpeed(); }
return getBaseSpeed() ‐ getLoadFactor() * numberOfCoconuts; }
} // Somewhere in client code speed = bird.getSpeed();
56
Summary
57
• Site : http://refactoring.com
References
• Book : Improving the Design of Existing Code (by Martin Fowler
58
• Eclipse examples
59