此时我们将printAllStudnetsInfo函数中读取数据部分的代码去掉,替换为调用loadAllStudentsFromDB函数,修改如下:
// 输出数据库中所有学生的信息 private void printAllStudnetsInfo() { // 从数据库中读取所有学生信息 List<Student>allStudents = loadAllStudentsFromDB() ; // 排序 Collections.sort(allStudents, new Comparator<Student>() { @Override public intcompare(Student lhs, Student rhs) { return (int) (lhs.id - rhs.id); } }); // 输出信息 for (Student student :allStudents) { System.out.println("### 学生信息 : " + student); } } |
此时,我们从数据库中读取所有学生信息的功能函数就提取出来了,函数名loadAllStudentsFromDB很好地说明了它的作用,当其他人看到这个函数时基本上一眼就能够看懂它的作用。另外,将这个功能独立出来之后,当其他函数需要这个功能时,直接调用该函数即可,而不必每次都输出同样的代码,造成太多的代码重复。代码重复的问题很多时候都是由于我们没有将一些功能函数更细小化,导致使用该功能时就直接写在需要这个功能的函数体中。
另外两个我们分别提炼出排序和输出信息的函数,函数名分别为sortStudents和printStudentsInfo。实现如下:
private void sortStudents(List<Student> students) {
Collections.sort(students, new Comparator<Student>() {
@Override
public intcompare(Student lhs, Student rhs) {
return (int) (lhs.id - rhs.id);
}
});
}
private void printStudentsInfo(List<Student> students) {
for (Student student : students) {
System.out.println("### 学生信息 : " + student);
}
}
最后我们的printAllStudnetsInfo函数修改如下:
// 输出数据库中所有学生的信息
protected void printAllStudnetsInfo() {
// 从数据库中读取所有学生信息
List<Student>allStudents = loadAllStudentsFromDB();
// 对学生数据进行升序排序
sortStudents(allStudents);
// 输出所有学生信息
printStudentsInfo(allStudents);
}
此时printAllStudnetsInfo中的代码就变得比较清晰了,适当的函数名加上简单的注释,printAllStudnetsInfo很容易理解,可读性得到了很大的提升。当我们需要修改其中的某个功能时,只需要进入到对应的函数进行修改,而不必担心会影响其他功能,提升了代码的可维护性。另外,更细粒度的函数更容易被复用,提升了代码的复用性。
提取子函数是重构手法中最为基础的,我们只有维持内部结构的清晰性才能够在更高的层次上进行重构。然而,很多长的函数并不像printAllStudnetsInfo函数按照逻辑功能划分开来,很多时候不同功能的代码都是夹杂在一起,这也正是它需要被重构的理由。此时,你需要在完全理解代码的前提下对这个"胖"函数进行"手术",将相关的变量通过参数传递给子函数、将结果返回给调用函数等,确保各个子函数能够正确工作,然后将它们替换到原来的函数中即可。
当每个类中的函数都相对比较清晰、简单的时候,如果有更高层次的结构问题我们也更容易识别出来,然后再进一步重构。
本文选自《Android开发进阶—从小工到专家》第十一章,本站经人民邮电出版社和作者的授权。
版权声明:51Testing软件测试网获人民邮电出版社和作者授权连载本书部分章节。
任何个人或单位未获得明确的书面许可,不得对本文内容复制、转载或进行镜像,否则将追究法律责任。
开发人员必备的技能之单元测试(4)—Android开发进阶