从Java的角度理解设计模式1:什么是重构 
MF在《重构》一书中是这样定义重构的:重构是这样一个过程,在不改变代码外在行为的前提下,对代码作出修改,以改进程序的内部结构。重构是一种有纪律的、经过训练的、有条不紊的程序整理方法,可以将整理过程中不小心引入错误的机率降到最低。本质上说,重构就是在代码写好之后改进它的设计。 
通常,软件开发总是先设计后编码,然而难免地,程序员编码风格的随意性、系统庞大化等诸多因素,导致代码质量将变得愈发难以控制。重构使得即使在面对糟糕设计,甚至是代码一片混乱的情况下,也能逐步改良代码的设计。大多数重构的步骤非常简单,比如为一个方法添加一个参数(Refactoring:Add Parameter)、(在类间)搬动一个方法(Refactoring :Move Method)、在类阶层中上下迁移代码:如值域(Refactoring :Push Up/Down Field)。然而正是这些微小的步骤,保障了代码朝着优良的结构持续演变,或者说不会日益“腐烂”。 
此外,重构的工作方法也使得所谓的精心设计不再如此举足轻重了,因为设计可以在持续重构中得到强化。 
如下展示了一个非常简单的重构,它采用了(Refactoring:Add Parameter): 
private void mainTestBody() { 
ApplicationContext context = 
new ClassPathXmlApplicationContext("ch6/prototype/setter-injection.xml"); 
BookList booklist = (BookList)context.getBean("bookList"); 
Book[] books = booklist.findBooksWrittenBy("天下霸唱"); 
assertEquals("鬼吹灯",books[0].getName()); 

private void mainTestBody(String configMetadata) { 
ApplicationContext context = 
new ClassPathXmlApplicationContext(configMetadata); 
BookList booklist = (BookList)context.getBean("bookList"); 
Book[] books = booklist.findBooksWrittenBy("天下霸唱"); 
assertEquals("鬼吹灯",books[0].getName()); 

本书对于重构剖析的侧重点有两个:一个是如何将重构应用于Java模式和框架设计的编程中;一个则是如何利用自动化重构工具对代码实施重构(当然并不是所有的重构技巧都得到工具支持)。 
本书对重构提供的阅读方法是:本章将会列出所有本书中用到的重构技巧名录(按字母顺序排列),而在后续各个章节中,对这些重构技巧的应用时机和方法会有更贴近实际的讲解;关于自动化重构工具的使用仅在本章列出,在后续章节中如果希望得到自动化的重构指导(对于每个重构技巧,如果自动化重构工具支持的话,都会有相应的指导),可参考本章。 

解决方案 »

  1.   

    从Java的角度理解设计模式2:自动化重构工具的使用
    重构的理论很具有吸引力,然而纯手工的重构需要检查的东西相当多,是一项耗时、易错的工作。也因为这个原因,很多程序员觉得重构的成本太大而不愿意进行重构。自动化重构工具的出现,大大改善了这个局面。现代化IDE融入重构功能后,使得编程和重构之间的差异也日益缩小(程序员几乎不再需要分辩“正在编程”还是“正在重构”),许多自动化的重构甚至基本都无须测试,重构成本也因此大大降低。 
    Java语言语法简洁清晰,是非常便于重构的一门语言,本书介绍的自动化重构工具便是一款成熟的Java IDE:Eclipse(使用的版本是3.3),读者可在http://www.eclipse.org/downloads/ 下载到Eclipse的最新版本。 
      

  2.   

    从Java的角度理解设计模式3:自动提炼方法
    下面将简单展示两个重构技巧“提炼方法(Refactoring:Extract Method)”和“搬移方法(Refactoring:Move Method)”如何通过Eclipse自动实施。给出原始代码,如下所示。 
    HelloBean.java 
    package ch2.extractandmovemethod.prototype; public class HelloBean { 
    public void sayHello() { 
    System.out.println("朋友,时刻重构吧!"); 


    RefactoringIDETest.java 
    package ch2.extractandmovemethod.prototype; public class RefactoringIDETest { 
    public static void main(String[] args) throws Exception { 
    String className = "ch2.refactoringusingide.HelloBean"; 
    Object beanInstance = null; 
    try { 
    Class clazz = Class.forName(className); 
    beanInstance = clazz.newInstance(); 
    } catch (Exception ex) { 
    throw ex; 

    ((HelloBean)beanInstance).sayHello(); 


    注意上述代码的框选部分,显然这部分代码可以被提炼出来形成一个公用方法。 
    说明:如果使用重构工具,只需简单地圈选出要提炼的段落,然后点选菜单选项“Extract Method”就行了。重构工具会自动检查被圈选的代码段是否可以提炼。代码无法提炼的原因有很多,可能是:它可能只包含部分标识符声明;可能对某个变量赋值而该变量又被其它代码用到。所有这些情况,程序员都完全不必担心,因为重构工具会自动识别并处理一切。随后,工具会自动计算出新方法所需的参数,并要求程序员为新方法取一个名字。此时,程序员可自行决定新方法参数的命名、排列顺序等。所有准备工作都完成后,重构工具会把圈选的代码从源方法中提炼出来,并在源方法中加入对新方法的调用。随后它会再源方法所属的类中建立新的方法,并以程序员指定的名称来命名该方法。整个重构过程耗时极短,且不会出错,相比手工进行这个重构,方便、安全了许多,体现了自动化重构工具的威力。 
    现在用Eclipse来实现上述步骤,首先选中上述代码的框选部分,点击鼠标右键,找到重构菜单“Refactor”,点选“Extract Method” (注意,重构菜单会自动识别出当前圈选的代码段有哪些重构技巧可用),如图1所示。 
    图1 自动化重构过程第一步 
    在随后出现的对话框中,为提炼出的新方法命名(命名为“instantiateClass”),并决定其它的方法签名(注意,为了后续可以不用修改地将此方法搬移到另一个工具类中,请选择“public”的方法访问权限),如图2所示。 
    图2 自动化重构过程第二步 
    点选“Preview”可预览重构所牵动的资源和结果,点选“OK”将直接进行重构,点选“Cancel”将放弃重构,当然即使在重构完成后,Eclipse也提供了强大的重构回复功能,可将所有牵动的代码回复到重构前的状态,甚至还有重构的历史回复功能。现在,点击“OK”,得到应用了(Refactoring:Extract Method)后的代码,如下所示。 
    RefactoringIDETest.java 
    package ch2.extractandmovemethod; import ch2.extractandmovemethod.prototype.HelloBean; public class RefactoringIDETest { 
    public static void main(String[] args) throws Exception { 
    String className = "ch2.refactoringusingide.HelloBean"; 
    Object beanInstance = instantiateClass(className); 
    ((HelloBean)beanInstance).sayHello(); 
    } public static Object instantiateClass(String className) throws Exception { 
    Object beanInstance = null; 
    try { 
    Class clazz = Class.forName(className); 
    beanInstance = clazz.newInstance(); 
    } catch (Exception ex) { 
    throw ex; 

    return beanInstance; 

    } 融智技术学苑(http://www.rzchina.net)版权所有,本公司致力于提供更好更实用的Java培训课程,帮助学员迅速成为编程的行家里手,更多Java面试题\Java视频\Java教程请访问我们的网站.转载请保留这段文字。
      

  3.   

    从Java的角度理解设计模式4:自动搬移方法
    接着,需要通过(Refactoring:Move Method)将这个方法搬移至一个工具类中,为此,简单的拟一个抽象工具类BeanUtils,如下所示。 BeanUtils.java package ch2.utils; public abstract class BeanUtils { } 
    回到上文的RefactoringIDETest类,在IDE中双击选中instantiateClass()方法名,点击鼠标右键,在重构菜单中,点选“Move”(IDE会自动识别选定的资源,比如本例选中的是方法,那么采用的重构技巧就是(Refactoring:Move Method)),如图3所示。 图3 自动化重构过程第三步 
    在随后的对话框中,找到刚才新建的BeanUtils类,点击“OK”,如图4所示。 图4 自动化重构过程第四步 
    在实施了所有自动化重构后,给出所有更动过的代码,如代码~2.2所示。 代码 BeanUtils.java package ch2.utils; public abstract class BeanUtils { public static Object instantiateClass(String className) throws Exception { 
    Object beanInstance = null; 
    try { 
    Class clazz = Class.forName(className); 
    beanInstance = clazz.newInstance(); 
    } catch (Exception ex) { 
    throw ex; 

    return beanInstance; 
    } } 代码 RefactoringIDETest.java package ch2.extractandmovemethod; import ch2.extractandmovemethod.prototype.HelloBean; 
    import ch2.utils.BeanUtils; public class RefactoringIDETest { 
    public static void main(String[] args) throws Exception { 
    String className = "ch2.refactoringusingide.HelloBean"; 
    Object beanInstance = BeanUtils.instantiateClass(className); 
    ((HelloBean)beanInstance).sayHello(); 


    上面演示了自动化重构工具(Eclipse3.3)的基本使用方法,下文将介绍更多的重构技巧(自动/非自动) 融智技术学苑(http://www.rzchina.net )版权所有,本公司致力于提供更好更实用的Java培训课程,帮助学员迅速成为编程的行家里手,更多Java面试题\Java视频\Java教程请访问我们的网站.转载请保留这段文字。 
      

  4.   

    从Java的角度理解设计模式5:自动改变方法签名
    (Refactoring:Change Method Signature)其实是Eclipse组合了《重构》一书中的几个重构技巧而成,它们分别是Add/Remove Parameter(增加/移除 方法参数)、Rename Method(重命名方法)。 
    1.动机 
    方法签名包含方法名、参数列(类型和次序)、方法返回类型、方法访问权限等,在编程的时候,改变方法签名有各种动机,比如当发现方法的名称未能明确揭示方法用途时,则需要改变方法名称(Refactoring:Rename Method);当发现某个方法需要从调用端得到更多信息时,则需要为方法添加参数(Refactoring:Add Parameter,见2.1节示例);当发现方法本体不再需要某个参数时,就需要移除参数(Refactoring:Remove Parameter),冗余的参数往往会给客户带来负担。 
    2.作法 
    以上这些重构技巧,在Eclipse中都可以通过重构菜单“Change Method Signature”来一并完成。给出原始的类,如下所示。 BeanFactory.java package ch2.changemethodsignature.prototype; import ch2.utils.BeanUtils; public class BeanFactory { 
    public Book getBook() throws Exception { 
    return (Book)BeanUtils.instantiateClass( 
    "ch2.changemethodsignature.prototype.Book"); 


    显然getBook()作为BeanFactory的主力工厂方法它不够通用,因此需要适当改变它的方法签名和实现。现在用Eclipse来实现上述步骤,首先双击选中getBook()方法,点击鼠标右键,找到重构菜单“Refactor”,点选“Change Method Signature”,在随后出现的对话框中,为getBook()方法重命名(命名为“getBean”);调整它的返回值为“Object”、访问权限为“public”;增加两个String型的参数“packageName”和“className”,如图5所示。 图5 自动改变方法签名 
    去掉方法内的强制转型后,得到初步重构后的代码,如下所示。 BeanFactory.java public class BeanFactory { 
    public Object getBean(String packageName, String className) throws Exception { 
    return BeanUtils.instantiateClass(packageName + className); 


    发现方法参数冗余,使用一个Bean的标识符就足够了。迅速作出再次重构,通过Eclipse的“Change Method Signature”菜单去掉一个参数(使用图5中的Remove按钮),并改变参数名称,得到最后的代码,如代码所示。 代码 BeanFactory.java package ch2.changemethodsignature; import ch2.utils.BeanUtils; public class BeanFactory { 
    public Object getBean(String beanIdentifier) throws Exception { 
    return BeanUtils.instantiateClass(beanIdentifier); 


    融智技术学苑(http://www.rzchina.net )版权所有,本公司致力于提供更好更实用的Java培训课程,帮助学员迅速成为编程的行家里手,更多Java面试题\Java视频\Java教程请访问我们的网站.转载请保留这段文字。