`
nbkangta
  • 浏览: 424344 次
  • 性别: Icon_minigender_1
  • 来自: 宁波
社区版块
存档分类
最新评论

《重构》读书笔记之数据重构

 
阅读更多

1. Self Encapsulate Field 自封装字段

 为字段建立Setter/Getter,并且只以这些函数来访问字段

做法:

为待封装字段建立取值/设置函数

找出该字段的所有引用点,将他们全部改为调用取值/设值函数

将该字段声明为private

复查,确保找出所有引用点

编译测试

 

2. Replace Data Value with Object 以对象取代数据值

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

做法:

为待替换数值新建一个类,在其中声明一个final字段,其类型和源类中的待替换数值类型一样,然后在新类中加入这个字段的取值函数,再加上一个接受此字段为参数的构造函数

编译

将源类中的待替换数值字段的类型改为前面新建的类

修改源类中该字段的取值函数,令它调用新类的取值函数

如果源类构造函数中用到这个待替换字段(多半是赋值动作),我们就修改构造函数,令它改用新类的构造函数来对字段进行赋值动作

修改源类中待替换字段的设置函数,令它为新类创建一个实例

编译测试

现在,你有可能需要新类使用Change Value to Refrence

 

3. Change Value to Reference 将值对象改为引用对象

从一个类衍生出许多彼此相等的实例,比如同样表示2010-1-1的日期对象,希望将他们替换为同一个对象

做法:

使用 Replace Constructor with Factory Method

编译测试

决定由什么对象负责提供访问新对象的途径,可能是一个静态字典或一个注册表对象

决定这些引用对象应该预先创建好,或是应该动态创建

修改工厂函数,令它返回引用对象

4. Change Reference to Value

有一个引用对象,很小且不可变,而且不易管理。这里有必要澄清一下“不可变”的意思。如果以Money类表示钱的概念,其中有“币种”和“金额”两条信息,那么Money对象通常是一个不可变的值对象。这并非意味你的薪资不能改变,而是意味:如果要改变你的薪资,就需要使用另一个Money对象来取代现有的Money对象,而不是在现有的Money对象上修改。

做法:

检查重构目标是否为不可变对象,或是否可修改为不可变对象

建立equals() 和 hashCode()

编译测试

考虑是否可以删除工厂函数,并将构造函数声明为public

 

5. Replace Array with Object 以对象取代数组

有一个数组,其中的元素各自代表不同的东西。以对象替换数组,对于数组中的每个元素,以一个字段来表示

 

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

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

 做法:

新建一个类表示数组所拥有的信息,并在其中以一个 public 字段保存原先的数组

修改数组的所有用户,让他们改用新类的实例

编译测试

逐一为数组元素添加Setter/Getter函数。根据元素的用途,为这些访问函数命名。修改客户端代码,让他们通过访问函数取用数组内的元素,每次修改后,编译并测试。

当所有对数组的直接访问都转而调用访问函数后,将新类中保存该数组的字段声明为private

编译

对于数组内的每一个元素,在新类中创建一个类型相当的字段。修改该元素的访问函数,令它改用上述的新建字段。

每修改一个元素,编译并测试

数组的所有元素都有了相应字段之后,删除该数组

 

6. Duplicate Observed Data 复制”被监视数据“

一些领域数据置身于GUI控件中,而领域函数需要访问这些数据,将该数据复制到一个领域对象中,建立一个Observer模式,用以同步领域对象和GUI对象内的重复数据。

该例比较复杂,请参考书内描述

 

7. Change Unidirectional Association to Bidirectional 将单向关联改为双向关联

两个类都需要使用对方特性,但其间只有一条单向连接。添加一个反向指针,并使修改函数能够同时更新两条连接

做法:

在被应用类中增加一个字段,用以保存反向指针

决定由哪个类——引用端还是被引用端——控制关联关系。如果是”一对多“关系,那么就由”拥有单一引用“的哪一方承担”控制者“角色。

在被控端建立一个辅助函数,其命名应该清楚指出它的有限用途

如果既有的修改函数在控制端,让它负责更新反向指针

如果既有的修改函数在被控端,就在控制端建立一个控制函数,并让既有的修改函数调用这个新建的控制函数。

 

8. Change Bidirectional Association to Unidirectional 将双向关联改为单向关联

去除不必要的关联

做法:

找出保存”你想去除的指针“的字段,检查它的每一个用户,判断是否可以去除该指针

如果客户使用了取值函数,先运用 Self Encapsulate Field 将待删除字段自我封装起来,然后使用 Substitute Algorithm 对付取值函数,令它不再使用该字段,然后编译测试。

如果客户并未使用取值函数,那就直接修改待删除字段的所有被引用点:改以其他途径获得该字段所保存的对象。每次修改后,编译并测试

如果已经没有热河函数使用待删除字段,移除所有对该字段的更新逻辑,然后移除该字段。

编译测试

 

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

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

 

10. Encapsulate Field 封装字段

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

 

11. Encapsulate Collection 封装集合

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

做法:

加入为集合添加/移除元素的函数

将保存集合的字段初始化为一个空集合

编译

找出集合设值函数的所有调用者。你可以修改那个设值函数,让它使用上述新建立的”添加/移除元素“函数;也可以直接修改调用端,改让他们调用上述新建立的”添加、移除元素“函数。

编译测试

找出所有”通过取值函数获得集合并修改其内容“的函数,逐一修改这些函数,让他们改用添加、移除函数。每次修改后,编译并测试

修改完上述所有”通过取值函数获得集合并修改集合内容“的函数后,修改取值函数自身,使它返回该集合的一个只读副本。使用Collection.unmodifiableXxxx()得到该集合的只读副本。

编译测试

找出取值函数的所有用户,从中找出应该存在于集合所属对象内的代码,运用Extract Method和Move Method将这些代码移到宿主对象去

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics