文章目录
  1. 1. Self Encapsulate Field(自封装字段)
    1. 1.1. Before Refactoring
    2. 1.2. After Refactoring
  2. 2. Replace Data Value with Object(以对象取代数据值)
    1. 2.1. Before Refactoring
    2. 2.2. After Refactoring
  3. 3. Change Value to Reference(将值对象改为引用对象)
    1. 3.1. Before Refactoring
    2. 3.2. After Refactoring
  4. 4. Change Reference to Value(将引用对象改为值对象)
  5. 5. Replace Array with Object(以对象取代数组)
    1. 5.1. Before Refactoring
    2. 5.2. After Refactoring
  6. 6. Duplicate Observed Data(复制“被监视数据”)
  7. 7. Change Unidirectional Association to Bidirectional(将单向关联改为双向关联)
    1. 7.1. Before Refactoring
    2. 7.2. After Refactoring
  8. 8. Change Bidirectional Association to Unidirectional(将双向关联改为单向关联)
    1. 8.1. Before Refactoring
    2. 8.2. After Refactoring
  9. 9. Replace Magic Number with Symbolic Constant(以字面常量取代魔法数)
    1. 9.1. Before Refactoring
    2. 9.2. After Refactoring
  10. 10. Encapsulate Field(封装字段)
  11. 11. Encapsulate Collection(封装集合)
    1. 11.1. Before Refactoring
    2. 11.2. After Refactoring
  12. 12. Replace Record with Data Class(以数据类取代纪录)
  13. 13. Replace Type Code with Class(以类取代类型码)
    1. 13.1. Before Refactoring
    2. 13.2. After Refactoring
  14. 14. Replace Type Code with Subclasses(以子类取代类型码)
    1. 14.1. Before Refactoring
    2. 14.2. After Refactoring
  15. 15. Replace Type Code with State/Strategy(以State/Strategy取代类型码)
    1. 15.1. Before Refactoring
    2. 15.2. After Refactoring
  16. 16. Replace Subclass with Fields(以字段取代子类)
    1. 16.1. Before Refactoring
    2. 16.2. After Refactoring

本章我们介绍几个让我们更加轻松处理数据的重构手法。

Self Encapsulate Field(自封装字段)

程序中直接访问一个字段,但是与字段之间的耦合关系逐渐变得笨拙。

可以为这个字段建立getter/setter函数,并且只以这些函数来访问字段。

Before Refactoring

private int _low, _high;
boolean includes (int arg) {
    return arg >= _low && arg <= _high;
}

After Refactoring

private int _low, _high;
boolean includes (int arg) {
    return arg >= getLow() && arg <= getHigh();
}

int getLow() {return _low;}
int getHigh() {return _high;}

间接访问变量的好处是,子类可以通过覆盖一个函数而改变获取数据的途径;还支持更灵活的数据管理,例如延迟初始化等。

直接访问变量的好处则是:代码比较容易阅读。

Replace Data Value with Object(以对象取代数据值)

有一个数据项,需要与其他数据和行为一起使用才有意义。

可以将数据项变成对象。

Before Refactoring

class Order...
    private String _customer;
    public Order (String customer) {
        _customer = customer;
    }
    public void setCustomer(String arg) {
        _customer = arg;
    }
    public String getCustomer() {
        return _customer;
    }

After Refactoring

class Order...
    private Customer _customer;
    public Order (String customerName) {
        _customer = new Customer(customerName);
    }
    public void setCustomer(String arg) {
        _customer = new Customer(arg);
    }
    public String getCustomer() {
        return _customer.getName();
    }

class Customer {
    private final String _name;
    public Customer(String name) {
        _name = name;
    }
    public String getName() {
        return _name;
    }
}

Change Value to Reference(将值对象改为引用对象)

从一个类衍生出许多彼此相等的实例,希望将它们替换为同一个对象。

可以将这个值对象变成引用对象。

Before Refactoring

class Order...
    private Customer _customer;
    public Order (String customerName) {
        _customer = new Customer(customerName);
    }
    public void setCustomer(String arg) {
        _customer = new Customer(arg);
    }
    public String getCustomer() {
        return _customer.getName();
    }

class Customer {
    private final String _name;
    public Customer(String name) {
        _name = name;
    }
    public String getName() {
        return _name;
    }
}

目前为止,Customer还是值对象。就算多份订单属于同一客户,但每个Order对象还是拥有各自的Customer对象。

After Refactoring

class Order...
    private Customer _customer;
    public Order (String customerName) {
        _customer = Customer.getNamed(customerName);
    }
    public void setCustomer(String arg) {
        _customer = Customer.getNamed(arg);
    }
    public String getCustomer() {
        return _customer.getName();
    }

class Customer {
    private static Dictionary _instance = new Hashtable();

    static void loadCustomers() {
        new Customer("Never").store();
        new Customer("xfh").store();
        new Customer("test").store();
    }
    private void store() {
        _instance.put(this.getName, this);
    }

    public static Customer getNamed(Stirng name) {
        return (Customer) _instance.get(name);
    }
}

Change Reference to Value(将引用对象改为值对象)

程序中有一个引用对象,很小且不可变,而且不易管理。

应该把它变成一个值对象。

值对象有一个非常重要的特性:它们应该是不可变的。如果对象是可变的,就不可以使用这项重构手段。

Replace Array with Object(以对象取代数组)

有一个数组,其中的元素各自代表不同的东西。

可以用对象替换数组。对于数组中的每个元素,以一个字段来表示。

Before Refactoring

String[] row = new String[3];
row[0] = "Liverpool";
row[1] = "15";

After Refactoring

Performance row = new Performance();
row.setName("Liverpool");
row.setWins("15");

Duplicate Observed Data(复制“被监视数据”)

有一些领域数据置身于GUI控件中,而领域函数需要访问这些数据。

应该将这些数据复制到一个领域对象中。建立一个Observer模式,用以同步领域对象和GUI对象内的重复数据。

Change Unidirectional Association to Bidirectional(将单向关联改为双向关联)

两个类都需要使用对方特性,但其间只有一条单向连接。

需要添加一个反向指针,并使改变函数能够同时更新两条连接。

Before Refactoring

class Order...
    private Customer _customer;
    public void setCustomer(Customer arg) {
        _customer = arg;
    }
    public String getCustomer() {
        return _customer;
    }

After Refactoring

由于一个用户拥有多份订单,所以可以在Customer中增加一个字段。

class Customer
    private Set _orders = new HashSet();

Change Bidirectional Association to Unidirectional(将双向关联改为单向关联)

两个类之间有双向关联,但其中一个类如今不再需要另一个类的特性。

应该去除不必要的关联。双向关联很有用,但必须为维护双向连接付出代价。

Before Refactoring

After Refactoring

Replace Magic Number with Symbolic Constant(以字面常量取代魔法数)

有一个字面数值,带有特别含义。

应该创建一个常量,根据其意义为它命名,并将上述字面数值替换为这个常量。

Before Refactoring

double potentialEnergy(double mass, double height) {
    return mass * 9.81 * height;
}

After Refactoring

double potentialEnergy(double mass, double height) {
    return mass*GRAVITATIONAL_CONSTANT*height;
}
static final double GRAVITATIONAL_CONSTANT = 9.81;

Encapsulate Field(封装字段)

类中存在一个public字段。应该把它声明为private,并提供相应的访问函数。

Encapsulate Collection(封装集合)

有一个函数返回一个集合。

应该让这个函数返回集合的一个只读副本,并在这个类中提供添加/移除集合元素的函数。

Before Refactoring

class Person...
    public Set getCourses() {
        return _courses;
    }
    public void setCourses(Set arg) {
        _courses = arg;
    }
    private Set _courses;

After Refactoring

class Person...
    public void addCourse(Course arg) {
        _courses.add(arg);
    }
    public void removeCourse(Course arg) {
        _courses.remove(arg);
    }
    private Set _courses = new HashSet();

    public Set getCourses() {
        return Collections.unmodifiableSet(_courses);
    }

Replace Record with Data Class(以数据类取代纪录)

需要面对传统环境中的记录结构。

为该记录创建一个“哑”数据对象。

Replace Type Code with Class(以类取代类型码)

类之中有一个数值类型码,但它并不影响类的行为。

可以用一个新的类型替换该数值类型码。

Before Refactoring

class Person {
    public static final int O = 0;
    public static final int A = 1;
    public static final int B = 2;
    public static final int AB = 3;

    private int _bloodGroup;
    public Person(int bloodGroup) {
        _bloodGroup = bloodGroup;
    }

    public void setBloodGroup(int arg) {
        _bloodGroup = arg;
    }
    public int getBloodGroup() {
        return _bloodGroup;
    }
}

After Refactoring

class Person {
    private BloodGroup _bloodGroup;
    public Person(int bloodGroup) {
        _bloodGroup = BloodGroup.code(bloodGroup);
    }

    public void setBloodGroup(int arg) {
        _bloodGroup = BloodGroup.code(arg);
    }
    public int getBloodGroup() {
        return _bloodGroup.getCode();
    }
}

class BloodGroup {
    public static final BloodGroup O = new BloodGroup(0);
    public static final BloodGroup A = new BloodGroup(1);
    public static final BloodGroup B = new BloodGroup(2);
    public static final BloodGroup AB = new BloodGroup(3);
    private static final BloodGroup[] _values = {O, A, B, AB};

    private final int _code;
    private BloodGroup(int code) {
        _code = code;
    }
    public int getCode() {
        return _code;
    }
    public static BloodGroup code(int arg) {
        return _values[arg];
    }
}

Replace Type Code with Subclasses(以子类取代类型码)

有个不可变的类型码,会影响类到行为。

应该使用子类取代这个类型码。

Before Refactoring

class Employee...
    private int _type;
    static final int ENGINEER = 0;
    static final int SALESMAN = 1;
    static final int MANAGER = 2;

    Employee (int type) {
        _type = type;
    }
    int getType() {
        return _type;
    }

After Refactoring

class Employee...
    private int _type;
    static final int ENGINEER = 0;
    static final int SALESMAN = 1;
    static final int MANAGER = 2;

    Employee (int type) {
        _type = type;
    }
    abstract int getType();
    static Employee create(int type) {
        switch (type) {
            case ENGINEER:
                return new Engineer();
            case SALESMAN:
                return new Salesman();
            case MANAGER:
                return new Manager();
            default:
                throw new IllegalArgumentException("....");
        }
    }
class Engineer extends Employee {
    int getType() {
        return Employee.ENGINEER;
    }
}
.......

Replace Type Code with State/Strategy(以State/Strategy取代类型码)

有一个状态码,会影响类到行为,但无法通过继承手段(类型码值在对象生命周期中发生变化或其他原因)消除它。

应该用状态对象取代类型码。

Before Refactoring

class Employee...
    private int _type;
    static final int ENGINEER = 0;
    static final int SALESMAN = 1;
    static final int MANAGER = 2;

    Employee (int type) {
        _type = type;
    }
    int payAmount() {
        switch (type) {
            case ENGINEER:
                return _mongthlySalary;
            case SALESMAN:
                return _mongthlySalary + _commission;
            case MANAGER:
                return _mongthlySalary + _bonus;
            default:
                throw new IllegalArgumentException("....");
        }
    }
    static Employee create(int type) {
        switch (type) {
            case ENGINEER:
                return new Engineer();
            case SALESMAN:
                return new Salesman();
            case MANAGER:
                return new Manager();
            default:
                throw new IllegalArgumentException("....");
        }
    }

After Refactoring

class Employee...
    private EmployeeType _type;

    Employee (int type) {
        _type = EmployeeType.newType(arg);
    }
    int payAmount() {
        switch (type) {
            case EmployeeType.ENGINEER:
                return _mongthlySalary;
            case EmployeeType.SALESMAN:
                return _mongthlySalary + _commission;
            case EmployeeType.MANAGER:
                return _mongthlySalary + _bonus;
            default:
                throw new IllegalArgumentException("....");
        }
    }
    int getType();
    static Employee create(int type) {
        switch (getType()) {
            case ENGINEER:
                return new Engineer();
            case SALESMAN:
                return new Salesman();
            case MANAGER:
                return new Manager();
            default:
                throw new IllegalArgumentException("....");
        }
    }

abstract class EmployeeType {
    static final int ENGINEER = 0;
    static final int SALESMAN = 1;
    static final int MANAGER = 2;
    abstract int getTypeCode();
    static EmployeeType newType(int code) {
        switch (code) {
            case ENGINEER:
                return new Engineer();
            case SALESMAN:
                return new Salesman();
            case MANAGER:
                return new Manager();
            default:
                throw new IllegalArgumentException("....");
        }
    }
}

class Engineer extends EmployeeType {
    int getTypeCode() {
        return EmployeeType.ENGINEER;
    }    
}

然后程序就可以使用Replace Conditional with Polymorphism来处理payAmount()函数了。

Replace Subclass with Fields(以字段取代子类)

各个子类的唯一差别只在“返回常量数据”的函数身上。

应该修改这些函数,使它们返回超类中的某个字段,然后销毁子类。

Before Refactoring

After Refactoring

文章目录
  1. 1. Self Encapsulate Field(自封装字段)
    1. 1.1. Before Refactoring
    2. 1.2. After Refactoring
  2. 2. Replace Data Value with Object(以对象取代数据值)
    1. 2.1. Before Refactoring
    2. 2.2. After Refactoring
  3. 3. Change Value to Reference(将值对象改为引用对象)
    1. 3.1. Before Refactoring
    2. 3.2. After Refactoring
  4. 4. Change Reference to Value(将引用对象改为值对象)
  5. 5. Replace Array with Object(以对象取代数组)
    1. 5.1. Before Refactoring
    2. 5.2. After Refactoring
  6. 6. Duplicate Observed Data(复制“被监视数据”)
  7. 7. Change Unidirectional Association to Bidirectional(将单向关联改为双向关联)
    1. 7.1. Before Refactoring
    2. 7.2. After Refactoring
  8. 8. Change Bidirectional Association to Unidirectional(将双向关联改为单向关联)
    1. 8.1. Before Refactoring
    2. 8.2. After Refactoring
  9. 9. Replace Magic Number with Symbolic Constant(以字面常量取代魔法数)
    1. 9.1. Before Refactoring
    2. 9.2. After Refactoring
  10. 10. Encapsulate Field(封装字段)
  11. 11. Encapsulate Collection(封装集合)
    1. 11.1. Before Refactoring
    2. 11.2. After Refactoring
  12. 12. Replace Record with Data Class(以数据类取代纪录)
  13. 13. Replace Type Code with Class(以类取代类型码)
    1. 13.1. Before Refactoring
    2. 13.2. After Refactoring
  14. 14. Replace Type Code with Subclasses(以子类取代类型码)
    1. 14.1. Before Refactoring
    2. 14.2. After Refactoring
  15. 15. Replace Type Code with State/Strategy(以State/Strategy取代类型码)
    1. 15.1. Before Refactoring
    2. 15.2. After Refactoring
  16. 16. Replace Subclass with Fields(以字段取代子类)
    1. 16.1. Before Refactoring
    2. 16.2. After Refactoring