大话重构连载7:重构是一系列的等量变换
程序员文章站
2022-03-02 13:35:12
...
毫无疑问,系统重构是一件如履薄冰、如坐针毡、你必须时时小心应对的工作,你就像走在钢丝上的人,每一步你都必须要保证正确,一个不经意的失误就可能让你万劫不复。尽管如此,只要你掌握了正确的方法,即使站在钢丝上也能如履平地,而这个正确的方法,就是那些被证明是正确的重构方法。说了那么多,你一定开始好奇,系统重构到底都是一些什么方法呢?行了,我也就不卖关子了,我们来看看重构方法工具箱里都有些什么东东。
系统重构要求我们对代码的每一步修改,都不能改变软件的外部行为,因此在系统重构中的所有方法,都是一种代码的等量变换。重构的过程,就好像在做数学题,一步一步地进行算式的等量变换。经过一系列等量变换,最终的结果虽然在形式上与原式不一样,但通过计算可以得到与原式完全相同的结果。
这种等量变换对于重构来说非常重要,它使得我们进行重构以后,程序还是那些程序,代码还是那些代码。但是,等量变换不等于原地踏步。正如矩阵通过等量变换可以得到方程组的解,微积分可以通过等量变换计算最终的结果,重构通过等量变换,在保证代码正确的同时,可以使程序结构得到优化。为了说明系统重构中的这种等量变换,我们来看看一个简单的例子,原始程序是这样的:
这是一个非常简单的HelloWorld程序,写得简单是为了大家更容易看懂程序的变换过程。这个程序虽然简单却符合遗留系统的许多特点:没有注释、顺序编程、没有层次、聚合度低,等等。因此我们进行了初步重构,增加注释、调整顺序、重命名变量、进行分段:
然后将两段注释中的代码分别提取出来形成getHour()与getSecondGreeting()函数:
通过这个例子我们可以看到,将没有先后顺序的语句调整编写顺序是一种等量变换,将语句中某段相对独立的语句提取出来形成一个函数,而让原语句调用这个函数,也是一种等量变换。除此之外,调整函数名称、修改变量名称等等,都是等量变换。等量变换,程序还是那些程序,执行的结果还是那些结果,但程序组织结构发生了变化,变得更加可读、可维护、易变更了,这就是重构的意义。
将密密麻麻的程序代码按照功能划分在数个函数中,可以有效地提高代码的可读性;将程序中各种各样的变量和函数合理地予以命名,并在函数头或定义处适时地进行注释,也是在提高代码可读性;将各种各样品种繁多的函数恰当地分配到各自的对象中合理地组织起来,则是在有效提高系统的可维护性与易变更性。这些对于一个遗留系统的日常维护与生命延续都是非常有帮助的。
大话重构连载首页:http://fangang.iteye.com/blog/2081995
特别说明:希望网友们在转载本文时,应当注明作者或出处,以示对作者的尊重,谢谢!
系统重构要求我们对代码的每一步修改,都不能改变软件的外部行为,因此在系统重构中的所有方法,都是一种代码的等量变换。重构的过程,就好像在做数学题,一步一步地进行算式的等量变换。经过一系列等量变换,最终的结果虽然在形式上与原式不一样,但通过计算可以得到与原式完全相同的结果。
这种等量变换对于重构来说非常重要,它使得我们进行重构以后,程序还是那些程序,代码还是那些代码。但是,等量变换不等于原地踏步。正如矩阵通过等量变换可以得到方程组的解,微积分可以通过等量变换计算最终的结果,重构通过等量变换,在保证代码正确的同时,可以使程序结构得到优化。为了说明系统重构中的这种等量变换,我们来看看一个简单的例子,原始程序是这样的:
public class HelloWorld { public String sayHello(Date now, String user){ Calendar c; int h; String s = null; c = Calendar.getInstance(); c.setTime(now); h = c.get(Calendar.HOUR_OF_DAY); if(h>=6 && h<12){ s = "Good morning!"; }else if(h>=12 && h<19){ s = "Good afternoon!"; }else{ s = "Good night!"; } s = "Hi, "+user+". "+s; return s; } }
这是一个非常简单的HelloWorld程序,写得简单是为了大家更容易看懂程序的变换过程。这个程序虽然简单却符合遗留系统的许多特点:没有注释、顺序编程、没有层次、聚合度低,等等。因此我们进行了初步重构,增加注释、调整顺序、重命名变量、进行分段:
/** * The Refactoring's hello-world program * @author fangang */ public class HelloWorld { /** * Say hello to everyone * @param now * @param user * @return the words what to say */ public String sayHello(Date now, String user){ //Get current hour of day Calendar calendar = Calendar.getInstance(); calendar.setTime(now); int hour = calendar.get(Calendar.HOUR_OF_DAY); //Get the right words to say hello String words = null; if(hour>=6 && hour<12){ words = "Good morning!"; }else if(hour>=12 && hour<19){ words = "Good afternoon!"; }else{ words = "Good night!"; } words = "Hi, "+user+". "+words; return words; } }
然后将两段注释中的代码分别提取出来形成getHour()与getSecondGreeting()函数:
/** * The Refactoring's hello-world program * @author fangang */ public class HelloWorld { /** * Say hello to everyone * @param now * @param user * @return the words what to say */ public String sayHello(Date now, String user){ int hour = getHour(now); return "Hi, "+user+". "+getSecondGreeting(hour); } /** * Get current hour of day. * @param now * @return current hour of day */ private int getHour(Date now){ Calendar calendar = Calendar.getInstance(); calendar.setTime(now); return calendar.get(Calendar.HOUR_OF_DAY); } /** * Get the second greeting. * @param hour * @return the second greeting */ private String getSecondGreeting(int hour){ if(hour>=6 && hour<12){ return "Good morning!"; }else if(hour>=12 && hour<19){ return "Good afternoon!"; }else{ return "Good night!"; } } }
通过这个例子我们可以看到,将没有先后顺序的语句调整编写顺序是一种等量变换,将语句中某段相对独立的语句提取出来形成一个函数,而让原语句调用这个函数,也是一种等量变换。除此之外,调整函数名称、修改变量名称等等,都是等量变换。等量变换,程序还是那些程序,执行的结果还是那些结果,但程序组织结构发生了变化,变得更加可读、可维护、易变更了,这就是重构的意义。
将密密麻麻的程序代码按照功能划分在数个函数中,可以有效地提高代码的可读性;将程序中各种各样的变量和函数合理地予以命名,并在函数头或定义处适时地进行注释,也是在提高代码可读性;将各种各样品种繁多的函数恰当地分配到各自的对象中合理地组织起来,则是在有效提高系统的可维护性与易变更性。这些对于一个遗留系统的日常维护与生命延续都是非常有帮助的。
大话重构连载首页:http://fangang.iteye.com/blog/2081995
特别说明:希望网友们在转载本文时,应当注明作者或出处,以示对作者的尊重,谢谢!