在这一章作者详细的介绍了一系列的重构手法,旨在优化代码中的数据组织方式,以提高代码的清晰度、可读性和可维护性。这是第八章中列举的一些重新组织数据的重构手法:
自封装字段(Self Encapsulate Field): 如果直接访问字段而不通过访问器方法,可以创建访问器方法,逐步替换对字段的直接访问。
// Before
public class MyClass {
public int myField;
// ...
public void someMethod() {
int value = myField;
// do something with value
}
}
// After
public class MyClass {
private int myField;
public int getMyField() {
return myField;
}
// ...
public void someMethod() {
int value = getMyField();
// do something with value
}
}
通过将字段封装在访问器方法中,我们提高了对字段的控制,并使得以后更容易修改其行为。
以对象取代数据值(Replace Data Value with Object): 使用多个字段表示某个概念时,可以将这个概念封装为一个对象。
// Before
public class Point {
public int x;
public int y;
// ...
public void moveTo(int newX, int newY) {
x = newX;
y = newY;
}
}
// After
public class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public void moveTo(int newX, int newY) {
// logic for moving to new coordinates
}
}
通过引入一个 Point 类,我们将点的概念更好地封装,使得代码更具表达力。
以值对象取代引用对象(Replace Reference with Value): 当对象的身份不重要,只关心其值时,将对象改为不可变的值对象,以便通过值比较进行比较。
// Before
public class Currency {
private String code;
public Currency(String code) {
this.code = code;
}
// ...
public boolean equals(Currency other) {
return this.code.equals(other.code);
}
}
// After
public class Currency {
private String code;
public Currency(String code) {
this.code = code;
}
public String getCode() {
return code;
}
// ...
}
通过将 Currency 类改为不可变的值对象,我们简化了对比逻辑,提高了可读性。
以子类取代类型码(Replace Type Code with Subclasses): 使用类型码来表示不同的类型时,为每个类型创建一个子类,以便通过多态来替代类型码。
// Before
public class Animal {
private int type;
public static final int DOG = 1;
public static final int CAT = 2;
// ...
public void makeSound() {
if (type == DOG) {
// dog sound
} else if (type == CAT) {
// cat sound
}
}
}
// After
public abstract class Animal {
// ...
public abstract void makeSound();
}
public class Dog extends Animal {
@Override
public void makeSound() {
// dog sound
}
}
public class Cat extends Animal {
@Override
public void makeSound() {
// cat sound
}
}
通过创建子类,我们使用了多态来代替类型码,使得代码更加灵活和可扩展。
引入外加数据(Introduce Foreign Data): 当需要在其他类中添加一些数据而不是在本地类中添加时,在本地类中创建一个字段,并通过方法在其他类中传递数据。
// Before
public class Order {
// ...
public double calculateTotalPrice(Customer customer) {
// use customer data for calculation
}
}
public class Customer {
// ...
}
// After
public class Order {
private Customer customer;
public double calculateTotalPrice() {
// use this.customer data for calculation
}
}
public class Customer {
// ...
}
通过引入外加数据,我们将数据传递逻辑更清晰地放置在了 Order 类中。
移除标志字段(Remove Flag Argument): 函数中使用标志字段来决定其行为时,将标志字段拆分为多个明确的参数,使得函数的行为更清晰。
// Before
public class Printer {
// ...
public void printDocument(String document, boolean isColor) {
if (isColor) {
// print color document
} else {
// print black and white document
}
}
}
// After
public class Printer {
// ...
public void printColorDocument(String document) {
// print color document
}
public void printBlackAndWhiteDocument(String document) {
// print black and white document
}
}
通过拆分标志字段,我们使函数的行为更加明确,提高了可读性。
以对象取代数组(Replace Array with Object): 使用数组表示一组相关的数据时,创建一个对象,将数组替换为对象的字段,使得数据更易于扩展和维护。
// Before
public class Team {
public String[] members;
// ...
}
// After
public class Team {
private List<String> members;
public Team(List<String> members) {
this.members = members;
}
// ...
}
通过引入对象,我们提高了对团队成员的控制,并使得相关数据更易于扩展。
以数据类取代记录(Replace Record with Data Class): 使用一组字段表示记录时,将字段封装为一个数据类,以提高代码的表达力。
// Before
public class Person {
public String name;
public int age;
// ...
}
// After
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// ...
}
通过引入数据类,我们使人物信息更清晰地封装,提高了代码的表达力。
以多态取代条件表达式(Replace Conditional with Polymorphism): 使用条件表达式来选择不同的行为时,使用多态将条件表达式替换为具体的子类,以实现更清晰的逻辑。
// Before
public abstract class Shape {
// ...
public void draw() {
if (this instanceof Circle) {
// draw circle
} else if (this instanceof Square) {
// draw square
}
}
}
// After
public interface Shape {
void draw();
}
public class Circle implements Shape {
// draw circle
}
public class Square implements Shape {
// draw square
}
通过使用多态,我们消除了条件表达式,使得代码更加简洁和易于扩展。
以观察者取代数据(Replace Data Value with Observer): 一个数据的变化需要通知其他地方,但使用了回调函数时,使用观察者模式将数据的变化通知到观察者。
// Before
public class Data {
private int value;
private List<Callback> callbacks;
// ...
public void setValue(int newValue) {
this.value = newValue;
notifyCallbacks();
}
private void notifyCallbacks() {
for (Callback callback : callbacks) {
callback.onValueChanged(value);
}
}
}
// After
public class Data extends Observable {
private int value;
// ...
public void setValue(int newValue) {
this.value = newValue;
setChanged();
notifyObservers(value);
}
}
通过引入观察者模式,我们使得数据变化通知更具扩展性,符合面向对象设计原则。
这些重新组织数据的重构手法有助于提高代码的清晰度、可读性和可维护性,同时使数据的组织方式更加合理。在应用这些手法时,需要仔细考虑系统的整体结构和需求,选择合适的手法进行优化。就像整理家里物品一样,通过精心的整理,让代码更加井然有序,易于管理和维护。