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.
References
 http://sourcemaking.com/refactoring
 http://en.wikipedia.org/wiki/Category:Software_desig
n_patterns

Refactoring Chapter11

  • 1.
    Refactoring: Improving theDesign of Existing Code Chapter 11 Dealing with Generalization Abner Huang 2013/10/11
  • 2.
    Generalization  Moving methodsaround a hierarchy of inheritance  Pull Up Field  Pull Up Method  Push Down Method  Push Down Field  Pull Up Constructor Body  ……
  • 3.
    12 techniques toclean a hierarchy of inheritance
  • 4.
    Push down Field If a field is used only by some subclasses, then move the field to those subclasses.
  • 5.
    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.
  • 6.
    Pull up Field Two subclasses have the same field. Move the field to the superclass.
  • 7.
    Push Down Method Behavior on a superclass is relevant only for some of its subclasses. Move it to those subclasses
  • 8.
     Declare amethod 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.
  • 9.
    Pull up Method You have methods with identical results on subclasses. Move them to the superclass
  • 10.
     If themethod 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.
  • 11.
    Pull up ConstructorBody  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() {};
  • 12.
    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 }
  • 13.
    Extract Subclass  Aclass has features that are used only in some instances. Create a subclass for that subset of features
  • 14.
    I’ll start witha 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; }
  • 15.
    We add thefollowing class class LaborItem ... public LaborItem (int quantity, Employee employee) { super (0, quantity, true); _employee = employee; }
  • 16.
    get rid ofthe isLabor field. class JobItem... protected boolean isLabor() { return false; } class LaborItem... protected boolean isLabor() { return true; }
  • 17.
    class JobItem... public intgetUnitPrice(){ return (isLabor()) ? _employee.getRate(): _unitPrice; } replace it with class JobItem... public int getUnitPrice(){return _unitPrice; } class LaborItem... public int getUnitPrice(){return _employee.getRate(); }
  • 18.
    Extract Superclass  Youhave two classes with similar features. Create a superclass and move the common features to the superclass.
  • 19.
    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.
  • 20.
    public class Department... publicDepartment (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(); . . .
  • 21.
     Use PullUp 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; }
  • 22.
     The methodsDepartment.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; }
  • 23.
    Extract Interface Several clientsuse the same subset of a class’s interface, or two classes have part of their interfaces in common.
  • 24.
    Collapse Hierarchy  Asuperclass and subclass are not very different. Merge them together.
  • 25.
    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() { … } … }
  • 26.
    1. Template Method[GoF]:  Build a template for functions for the same tasks with the same workflow 2. Pull up Method
  • 27.
    class Customer... public Stringstatement() { 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); }
  • 28.
    Replace Inheritance withDelegation  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.
  • 29.
    Replace Delegation withInheritance  You’re using delegation and are often writing many simple delegations for the entire interface. Make the delegating class a subclass of the delegate.
  • 30.
     A coupleof 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.
  • 32.