A class has features that are only used by some instances.

Create a new subclass. Iteratively push down methods and features.

Our Aircraft class contains a hover method only certain types of aircraft don't perform:
class Aircraft {
private double speed, altitude;
private boolean canHover = false;
public double getSpeed() { return
speed; }
private void setSpeed(double s) {
speed = s; }
public double getAltitude() { return
altitude; }
private void setAltitude(double a) {
altitude = a; }
public void hover() {
altitude = 100;
speed = 0;
}
public void fly() {
// etc.
if (canHover) hover();
}
}
Introduce a new subclass:
class Helicopter extends Aircraft { }
Push helicopter specific methods down into the subclass:
class Helicopter extends Aircraft {
public void hover() {
setAltitude(100);
setSpeed(0);
}
public void fly() {
super.fly();
hover();
}
}
Remove methods and fields from super class. It may be necessary to change the scope of some members:
public class Aircraft {
private double speed, altitude;
//protected boolean canHover =
false;
public double getSpeed() { return
speed; }
protected void setSpeed(double s) {
speed = s; }
public double getAltitude() { return
altitude; }
protected void setAltitude(double a)
{ altitude = a; }
public void fly() {
//if (canHover) hover();
}
}
Two classes have similar features. This is a form of code duplication.

Introduce an abstract superclass. Iteratively use Pull Up Field, Pull Up Method, and Pull Up Constructor Body. Extract Method can be used to extract and pull up common tasks within methods.

class Helicopter {
private double speed, altitude;
public void takeoff() { }
public void fly() { }
public void land() { }
public void hover() { }
}
class Airplane {
private double _speed, _altitude;
public void takeoff() { }
public void fly() { }
public void land() { }
public void bank() { }
}
Introduce a new abstract superclass:
abstract class Airplane { }
Use Pull Up Field to move common fields to the new superclass. Be sure the fields are used in the same way. This might also require renaming some of the fields:
abstract class Aircraft {
protected double speed, altitude;
}
class Helicopter extends Aircraft {
public void takeoff() { }
public void fly() { }
public void land() { }
public void hover() { }
}
class Airplane extends Aircraft {
public void takeoff() { }
public void fly() { }
public void land() { }
public void bank() { }
}
Pull up each method. This may require changing the signature of some methods:
abstract class Aircraft {
protected double speed, altitude;
public void takeoff() { }
public void fly() { }
public void land() { }
}
class Helicopter extends Aircraft {
public void hover() { }
}
class Airplane extends Aircraft {
public void bank() { }
}
Common tasks performed inside bank() and hover() can be extracted into methods that get pulled up to the superclass.
Behavior is determined by a type tag. This can lead to complex and ubiquitous multi-way conditionals that perform type tag dispatches.

For each value of the type tag introduce a subclass that overrides any methods containing dispatches.

A superclass and a subclass are not very different.

Choose which class to eliminate. Iteratively apply Pull Up Method/Field or Push Down Method/Field.

A subclass only uses part of what it inherits from a superclass. Alternatively, objects need to dynamically alter the implementation of their superclass.

Add a reference to the superclass. Qualify all calls to inherited methods by this reference. Remove superclass declaration.

Too many delegation operations must be performed.

Make the delegate class the superclass. Remove qualifiers from calls to delegate methods. Remove delegate reference.

Bidirectional associations add to the complexity of a program.

Zombies: Objects that should be dead but are still around because of an uncleared reference.
If a back reference is no longer needed, then eliminate it.

A back link is required.

Decide which class will control the association.

The identity of a value object is determined by its fields. Two value objects are the same if and only if their fields are the same. Value objects should be immutable. Dates, numbers, and quantities are examples of value objects. It doesn't matter if a program contains multiple value objects that are the same.
The identity of a reference object is determined by what it represents. Two reference objects are the same if they both represent the same thing. Entities, events, and types are examples of reference objects. Having multiple objects in a program that represent the same thing can lead to synchronization problems and confusion.

Replace Part constructor with a static factory method that only creates new instances when needed.

class Customer {
private String name;
public String getName() { return name;
}
public Customer(String name) {
this.name = name; }
public boolean equals(Object other) {
if (other == null) return false;
if (other.getClass() !=
this.getClass()) return false;
Customer cust = (Customer)other;
return name.equals(cust.getName());
}
// etc.
}
public class Order {
private Customer customer;
public Customer getCustomer() { return
customer; }
public Order(String customerName) {
customer = new
Customer(customerName);
}
// etc.
}
if (customer.equals(order.getCustomer())) { ... }
Step 1: Replace the constructor of the value class by a factory method:
class Customer {
private String name;
public String getName() { return name;
}
public static Customer
makeCustomer(String name) {
return new Customer(name);
}
private Customer(String name) {
this.name = name; }
public boolean equals(Object other) {
if (other == null) return false;
if (other.getClass() !=
this.getClass()) return false;
Customer cust = (Customer)other;
return name.equals(cust.getName());
}
// etc.
}
public class Order {
private Customer customer;
public Customer getCustomer() { return
customer; }
public Order(String customerName) {
customer = Customer.makeCustomer(customerName);
}
// etc.
}
Step 2: Alter the factory method to return a reference:
class Customer {
private String name;
public String getName() { return name;
}
private static Map registry = new
Hashtable();
public static Customer
makeCustomer(String name) {
Customer cust = (Customer)
registry.get(name);
if (cust == null) {
cust = new Customer(name);
registry.put(name, cust);
}
return cust;
}
private Customer(String name) {
this.name = name;
}
// etc.
}
We may want to add a new Order constructor:
public Order(Customer
customer) {
this.customer = customer;
}
Immutable objects don't really need to be references.

Add equals and hash methods to value class that respect logically equality:

The center of a circle is a point:
class Circle {
Point center;
double radius;
// etc.
}
A point is completely determined by its x and y coordinates, which can't be changed:
class Point {
double xc, yc;
public String toString() {
return "(" + xc + ",
" + yc + ")";
}
// etc.
}
We override the inherited equality, which simply tests for literal equality, with a version that tests for logical equality. To make hash tables work properly, we must also replace the inherited hash code function with one that guarantees logically distinct points will have different hash codes:
class Point {
private double xc, yc;
public String toString() {
return "(" + xc + ",
" + yc + ")";
}
public boolean equal(Object other) {
if (other == null) return false;
if (other.getClass() != getClass())
return false;
Point p = (Point)other;
return p.xc == xc && p.yc ==
yc;
}
public int hashCode() {
return toString().hashCode();
}
// etc.
}







