Refactoring Chapter11

32
Refactoring: Improving the Design of Existing Code Chapter 11 Dealing with Generalization Abner Huang 2013/10/11

Transcript of Refactoring Chapter11

Refactoring: Improving the Design of Existing Code

Chapter 11

Dealing with Generalization

Abner Huang

2013/10/11

Generalization Moving methods around a hierarchy of

inheritance

Pull Up Field

Pull Up Method

Push Down Method

Push Down Field

Pull Up Constructor Body

……

12 techniques to clean a hierarchy of inheritance

Push down Field If a field is used only by some subclasses, then move

the field to those subclasses.

Push down Field (cont.) Declare the field in all subclasses.

Remove the field from the superclass.

Compile and test.

Remove the field from all subclasses that don’t need it.

Compile and test.

Pull up Field Two subclasses have the same field. Move the field to

the superclass.

Push Down Method Behavior on a superclass is relevant only for some of its

subclasses. Move it to those subclasses

Declare a method in all subclasses and copy the body into each subclass.

Remove method from superclass.

Compile and test.

Remove the method from each subclass that does not need it.

Compile and test.

Pull up Method You have methods with identical results on subclasses.

Move them to the superclass

If the method calls another method that is present on both subclasses but not the superclass, declare an abstract method on the superclass.

If the method uses a subclass field, use Pull Up Field or Self Encapsulate Field and declare and use an abstract getting method.

Pull up Constructor Body You have constructors on subclasses with mostly

identical bodies. Create a superclass constructor; call this from the subclass methods.

Use super() in JAVA

C++ has no super(); it use child_ctor(): parent_ctor() {};

class Employee...

protected String _name;

protected String _id;

boolean isPriviliged() {..}

void assignCar() {..}

class Manager...

private int _grade;

public Manager (String name, String id, int grade) {

super (name, id);

_grade = grade;

if (isPriviliged()) assignCar();

//every subclass does this

}

Extract Subclass A class has features that are used only in some

instances. Create a subclass for that subset of features

I’ll start with a job item class that determines prices for items of work at a local garage. If we have the following code

class JobItem ...

public JobItem (int unitPrice, int quantity, boolean isLabor, Employee employee) {

_unitPrice = unitPrice;

_quantity = quantity;

_isLabor = isLabor;

_employee = employee;

}

public int getUnitPrice(){

return (_isLabor)? _employee.getRate(): _unitPrice;

}

We add the following class

class LaborItem ...

public LaborItem (int quantity, Employee employee) {

super (0, quantity, true);

_employee = employee;

}

get rid of the isLabor field.

class JobItem...

protected boolean isLabor() {

return false;

}

class LaborItem...

protected boolean isLabor() {

return true;

}

class JobItem...

public int getUnitPrice(){

return (isLabor()) ? _employee.getRate(): _unitPrice;

}

replace it with class JobItem...

public int getUnitPrice(){return _unitPrice; }

class LaborItem...

public int getUnitPrice(){return _employee.getRate(); }

Extract Superclass You have two classes with similar features. Create a

superclass and move the common features to the superclass.

class Employee...

public Employee (String name, String id, int annualCost) {

_name = name;

_id = id;

_annualCost = annualCost;

}

private String _name;

private int _annualCost;

private String _id;

. . .

//And their getters.

public class Department...

public Department (String name) {

_name = name;

}

public int getTotalAnnualCost(){

Enumeration e = getStaff();

int result = 0;

while (e.hasMoreElements()) {

Employee each = (Employee) e.nextElement();

result += each.getAnnualCost();

}

return result;

}

private String _name;

private Vector _staff = new Vector();

. . .

Use Pull Up Constructor Body to assign the name class Party...

protected Party (String name) { _name = name; }

private String _name;

class Department...

public Department (String name) { super (name); }

class Employee...

public Employee (String name, String id, int annualCost) {

super (name);

_id = id;

_annualCost = annualCost;

}

The methods Department.getTotalAnnualCost and Employee.getAnnualCost, do carry out the same intention, so they should have the same name. cannot use Pull Up Method

Add abstract public int getAnnualCost() to superclass.

class Department...

public int getAnnualCost(){

Enumeration e = getStaff();

int result = 0;

while (e.hasMoreElements()) {

Party each = (Party) e.nextElement();

result += each.getAnnualCost();

}

return result;

}

Extract Interface Several clients use the same subset of a class’s interface,

or two classes have part of their interfaces in common.

Collapse Hierarchy A superclass and subclass are not very different. Merge

them together.

Form Template Method You have two methods in subclasses that perform

similar steps in the same order, yet the steps are different.

Class Customer {

public String statement() { … }

public String html_statement() { … }

}

1. Template Method [GoF]:

Build a template for functions for the same tasks with the same workflow

2. Pull up Method

class Customer...

public String statement() {

return new TextStatement().value(this);}

public String htmlStatement() {

return new HtmlStatement().value(this);}

class Statement...

abstract String headerString(Customer aCustomer);

abstract String eachRentalString (Rental aRental);

abstract String footerString (Customer aCustomer);

public String value(Customer aCustomer) {

out = headerString(aCustomer);

while (rentals.hasMoreElements()) {

out += eachRentalString(each);

}

out += footerString(aCustomer);

}

Replace Inheritance with Delegation

A subclass uses only part of a superclasses interface or does not want to inherit data. Create a field for the superclass, adjust methods to delegate to the superclass, and remove the subclassing.

Replace Delegation with Inheritance You’re using delegation and are often writing many

simple delegations for the entire interface. Make the delegating class a subclass of the delegate.

A couple of caveats

Don’t use this technique, if you aren’t using all the methods of the class to which you are delegating

beware of is that in which the delegate is shared by more than one object and is mutable.