`
z75148885
  • 浏览: 185821 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

java重构文档(改造bad smell)

阅读更多

1.重构要求

1)安全第一,尤其是关键部分,应先做出一demo,各环节正常测试运行后无缝割接。

周五和下班前提交更要小心,更改后的代码一定要及时放cvs,并在提交时注明修改的地方或原因,告同组的项目组员。

2)重构要先有接口测试,重构后必须保证通过接口测试,因为现在的系统是一个正常运行的系统,如果把未测试通过的代码放服务器,势必会给公司带来损失。

所以要求:小步进行,意思是每做改动,均要测试和可回朔。

3)重构完成后,向服务器提交代码时,需采用更保险的方法,将原文件备份为以***.class.20060809.jeff的文件,不能简单的覆盖,否则那是很危险的。

4)遇正常工作任务时先做正常任务,完成后继续重构,不能以重构为借口推工作。

5)这次总结的方式方法,经验形成文档,要求以后在工作中是随时做的,当增加功能时,修改bug时或复审代码时都应该想到是否将原有的代码重构,以提高系统的可复用性和可扩展性。

2.重构的工作

1) 名字重构,修改原有不合理的名字。(参考java开发技术规范)

2) 包,结构重构,重整原有的结构,合并和细分。(参考java开发技术规范)

3) 方法体重构,长方法抽取,方法公用

4)在正确的类里计算值,不要在别的类里计算和写逻辑有本类的东西。

5)配置文件的重整

6)编码效率的重构:

a) 循环内不许声明变量

b) 尽可能不要在循环内做判断

c) StringBuffer

d) 连接池

e) 缓存

7) 非有用文件的及时删除

8log的整理

9)文档的整理

10异常的处理 (参看下面的例子)

11)参考java开发技术规范

3代码的bad smell

1) 重复的代码: Extract method

2) 过长函数: 重构成small method 后要能取个好名字。

有这样一个原则:每当感觉需要以注析来说明点什么的时候,我们就把需要说明的东西写进一个独立函数中,并以其用途(而非实现手法)命名,我们可以对一组甚至短短一行代码做这件事。

如何确定该提炼哪一段代码呢,一个很好的技巧是:寻找注析。

条件式和循环常常也是提炼的信号。

3)过大类,一个class做太多事情,分开,提炼时应该选择class内彼此相关的变量,将他们放在一起。

4)过长参数列: 改成传对象,谨慎。

5)发散式变化:当你看着一个class说:o,如果新加入一个数据库,我必须修改这三个函数...,那么此时也许将这个对象分成两个会更好,这样一来每个对象都可以只因一种变化而需要修改。

6)霰弹式修改:如果遇到某种变化,你都必须在许多不同的classes内做出许多小修改以响应之,你不但很难找到他们,也很容易忘记某个重要的修改,可以把需要修改的代码放进同一个class.

7) 依恋情节:

我们看到某个函数为了计算某值,从另一个对象哪儿调用几乎半打的取值函数(getting method,疗法是把这个函数移至它该去的另一个地方,Move method.

8) 数据泥团 你常常可以看到很多地方有相同的三或四笔数据项:两个classes内的相同值域,许多函数中的相同参数,这些总是绑在一起出现的数据,真应该放进属于他们自己的 对象中。

处理java异常的例子

你觉得自己是一个Java专家吗?是否肯定自己已经全面掌握了Java的异常处理机制?在下面这段代码中,你能够迅速找出异常处理的六个问题吗?

1 OutputStreamWriter out = ...
2 java.sql.Connection conn = ...
3 try { //

4
 Statement stat = conn.createStatement();
5
 ResultSet rs = stat.executeQuery(
6
  "select uid, name from user");
7
 while (rs.next())
8
 {
9
  out.println("ID" + rs.getString("uid") //
10
   ",姓名:" + rs.getString("name"));
11
 }
12
 conn.close(); //
13
 out.close();
14 }
15 catch(Exception ex) //

16 {
17
 ex.printStackTrace(); //⑴,⑷
18 }

反例之一:丢弃异常   

代码:15-18行。
  这段代码捕获了异常却不作任何处理,可以算得上Java编程中的杀手。从问题出现的频繁程度和祸害程度来看,它也许可以和C/C++程序的一个恶名远播的问题相提并论??不检查缓冲区是否已满。如果你看到了这种丢弃(而不是抛出)异常的情况,可以百分之九十九地肯定代码存在问题(在极少数情况下,这段代码有存在的理由,但最好加上完整的注释,以免引起别人误解)。

那么,应该怎样改正呢?主要有四个选择:

  1、处理异常。针对该异常采取一些行动,例如修正问题、提醒某个人或进行其他一些处理,要根据具体的情形确定应该采取的动作。再次说明,调用printStackTrace算不上已经“处理好了异常”。

  2、重新抛出异常。处理异常的代码在分析异常之后,认为自己不能处理它,重新抛出异常也不失为一种选择。

  3、把该异常转换成另一种异常。大多数情况下,这是指把一个低级的异常转换成应用级的异常(其含义更容易被用户了解的异常)。

  4、不要捕获异常。

  结论一:既然捕获了异常,就要对它进行适当的处理。不要捕获异常之后又把它丢弃,不予理睬。

反例之二:不指定具体的异常

  代码:15行。

  许多时候人们会被这样一种“美妙的”想法吸引:用一个catch语句捕获所有的异常。最常见的情形就是使用catch(Exception ex)语句。但实际上,在绝大多数情况下,这种做法不值得提倡。为什么呢?

  要理解其原因,我们必须回顾一下catch语句的用途。catch语句表示我们预期会出现某种异常,而且希望能够处理该异常。异常类的作用就是告诉Java编译器我们想要处理的是哪一种异常。由于绝大多数异常都直接或间接从java.lang.Exception派生,catch(Exception ex)就相当于说我们想要处理几乎所有的异常。

  再来看看前面的代码例子。我们真正想要捕获的异常是什么呢?最明显的一个是SQLException,这是JDBC操作中常见的异常。另一个可能的异常是IOException,因为它要操作OutputStreamWriter。显然,在同一个catch块中处理这两种截然不同的异常是不合适的。如果用两个catch块分别捕获SQLExceptionIOException就要好多了。这就是说,catch语句应当尽量指定具体的异常类型,而不应该指定涵盖范围太广的Exception类。

  另一方面,除了这两个特定的异常,还有其他许多异常也可能出现。例如,如果由于某种原因,executeQuery返回了null,该怎么办?答案是让它们继续抛出,即不必捕获也不必处理。实际上,我们不能也不应该去捕获可能出现的所有异常,程序的其他地方还有捕获异常的机会??直至最后由JVM处理。

  结论二:在catch语句中尽可能指定具体的异常类型,必要时使用多个catch。不要试图处理所有可能出现的异常。

 反例之三:占用资源不释放

  代码:3-14行。

  异常改变了程序正常的执行流程。这个道理虽然简单,却常常被人们忽视。如果程序用到了文件、SocketJDBC连接之类的资源,即使遇到了异常,也要正确释放占用的资源。为此,Java提供了一个简化这类操作的关键词finally

  finally是样好东西:不管是否出现了异常,Finally保证在try/catch/finally块结束之前,执行清理任务的代码总是有机会执行。遗憾的是有些人却不习惯使用finally

  当然,编写finally块应当多加小心,特别是要注意在finally块之内抛出的异常??这是执行清理任务的最后机会,尽量不要再有难以处理的错误。

  结论三:保证所有资源都被正确释放。充分运用finally关键词。

 反例之四:不说明异常的详细信息

  代码:3-18行。

  仔细观察这段代码:如果循环内部出现了异常,会发生什么事情?我们可以得到足够的信息判断循环内部出错的原因吗?不能。我们只能知道当前正在处理的类发生了某种错误,但却不能获得任何信息判断导致当前错误的原因。

  printStackTrace的堆栈跟踪功能显示出程序运行到当前类的执行流程,但只提供了一些最基本的信息,未能说明实际导致错误的原因,同时也不易解读。

  因此,在出现异常时,最好能够提供一些文字信息,例如当前正在执行的类、方法和其他状态信息,包括以一种更适合阅读的方式整理和组织printStackTrace提供的信息。

  结论四:在异常处理模块中提供适量的错误原因信息,组织错误信息使其易于理解和阅读。 

反例之五:过于庞大的try

  代码:3-14行。

  经常可以看到有人把大量的代码放入单个try块,实际上这不是好习惯。这种现象之所以常见,原因就在于有些人图省事,不愿花时间分析一大块代码中哪几行代码会抛出异常、异常的具体类型是什么。把大量的语句装入单个巨大的try块就象是出门旅游时把所有日常用品塞入一个大箱子,虽然东西是带上了,但要找出来可不容易。

  一些新手常常把大量的代码放入单个try块,然后再在catch语句中声明Exception,而不是分离各个可能出现异常的段落并分别捕获其异常。这种做法为分析程序抛出异常的原因带来了困难,因为一大段代码中有太多的地方可能抛出Exception

  结论五:尽量减小try块的体积。

 反例之六:输出数据不完整

  代码:7-11行。

  不完整的数据是Java程序的隐形杀手。仔细观察这段代码,考虑一下如果循环的中间抛出了异常,会发生什么事情。循环的执行当然是要被打断的,其次,catch块会执行??就这些,再也没有其他动作了。已经输出的数据怎么办?使用这些数据的人或设备将收到一份不完整的(因而也是错误的)数据,却得不到任何有关这份数据是否完整的提示。对于有些系统来说,数据不完整可能比系统停止运行带来更大的损失。

  较为理想的处置办法是向输出设备写一些信息,声明数据的不完整性;另一种可能有效的办法是,先缓冲要输出的数据,准备好全部数据之后再一次性输出。

  结论六:全面考虑可能出现的异常以及这些异常对执行流程的影响。

改写后的代码

  根据上面的讨论,下面给出改写后的代码。也许有人会说它稍微有点罗嗦,但是它有了比较完备的异常处理机制。

OutputStreamWriter out = ...
java.sql.Connection conn = ...
try {
 Statement stat = conn.createStatement();
 ResultSet rs = stat.executeQuery(
  "select uid, name from user");
 while (rs.next())
 {
  out.println("ID" + rs.getString("uid") + ",姓名: " + rs.getString("name"));
 }
}
catch(SQLException sqlex)
{
 out.println("警告:数据不完整");
 throw new ApplicationException("读取数据时出现SQL错误", sqlex);
}
catch(IOException ioex)
{
 throw new ApplicationException("写入数据时出现IO错误", ioex);
}
finally
{
 if (conn != null) {
  try {
   conn.close();
  }
  catch(SQLException sqlex2)
  {
   System.err(this.getClass().getName() + ".mymethod - 不能关闭数据库连接: " + sqlex2.toString());
  }
 }

 if (out != null) {
  try {
   out.close();
  }
  catch(IOException ioex2)
  {
   System.err(this.getClass().getName() + ".mymethod - 不能关闭输出文件" + ioex2.toString());
  }
 }
}

本文的结论不是放之四海皆准的教条,有时常识和经验才是最好的老师。如果你对自己的做法没有百分之百的信心,务必加上详细、全面的注释。

  另一方面,不要笑话这些错误,不妨问问你自己是否真地彻底摆脱了这些坏习惯。即使最有经验的程序员偶尔也会误入歧途,原因很简单,因为它们确确实实带来了“方便”。所有这些反例都可以看作Java编程世界的恶魔,它们美丽动人,无孔不入,时刻诱惑着你。也许有人会认为这些都属于鸡皮蒜毛的小事,不足挂齿,但请记住:勿以恶小而为之,勿以善小而不为。

分享到:
评论
1 楼 MayBe_you 2016-04-11  

相关推荐

    java重构设计.doc

    1.重构要求 2.重构的工作 3.代码的bad smell 4. 重构的例子

    Code Bad Smell Detector-开源

    这个项目是一个基于Java的检测器,可以检测Fowler等人的五个。 (1999) 的代码不良气味:数据块、开关语句、推测一般性、消息链和中间人,来自 Java 源代码。

    A Textual-based Technique for Smell Detection

    论文《A Textual-based Technique for Smell Detection》pdf全

    重构 小抄 Smells to Refactorings

    顶级程序员培训公司Industrial Logic, Inc. 提供。重构技术的随身小纸条,详尽的代码坏味和对应的重构。强烈推荐给读过《重构:改善既有代码的设计》的人

    findbugs检查工具

    findbugs是一个开源的eclipse 代码检查工具;它可以简单高效全面地帮助我们发现程序代码中存在的bug,bad smell,以及潜在隐患. 下载的文件包含如下: 1.findbugs的eclipse插件source包 2.安装及使用说明文档

    coca-master.zip

    Coca 是一个用于系统重构、系统迁移和系统分析的工具箱。它可以分析代码中的 badsmell,行数统计,分析调用与依赖,进行 Git 分析,以及自动化重构等。

    Smell Agent Optimization.zip气味剂算法及其原文

    分享了气味剂算法源代码及其原文,更多算法可进入空间查看

    沪教版一年级英语下册(牛津版) Unit 3 Taste and smell 第1课时 教案 教学设计 .pdf

    沪教版一年级英语下册(牛津版) Unit 3 Taste and smell 第1课时 教案 教学设计 .pdf

    code_smell_extractor_ci:代码气味提取器在github上的项目

    code_smell_extractor_ci 代码气味提取器在github上的项目安装要做Git: : PMD: : 系统开发Linux运行程序您必须在linux上,并且必须修改src / main / java / utilities / Utility.java中的变量: PATH_PMD =“ [您...

    qualinsight-plugins-sonarqube-smell:用于SonarQube和配套Java库的Code Smells插件

    安装和使用文档位于。 非常欢迎新功能的想法和。 已创建一个名为,以促进有关此插件的讨论。 希望您会喜欢我喜欢编写的这个小插件! 请不要犹豫,请求新的代码气味类型,发送评论以及进行改进。

    检测JavaScript类的内聚耦合Code Smell.pdf

    检测JavaScript类的内聚耦合Code Smell.pdf

    Automatic-Code-Smell-Detector:IntelliJ插件专注于自动检测和纠正Java代码中的代码气味

    自动代码气味检测器自动代码气味检测器是IntelliJ IDEA插件,致力于自动检测和纠正Java代码中的代码气味。下载及安装可以按照以下步骤直接在IntelliJ IDEA中下载该插件: 按Ctrl + Alt + S或选择文件| 设置(适用于...

    code-smell-refactoring:几种语言中各种代码异味的小例子

    代码味道重构练习 此存储库中的每个分支都有给定语言的练习。 原始源材料(在java分支中)是来自(C) Jason Gorman。 有关 TDD 和重构代码异味,请查看。

    findbugs-1.3.9.tar.zip

    findbugs是一个开源的代码检查工具;它可以简单高效全面地帮助我们发现程序代码中存在的bug,bad smell,以及潜在隐患。

    jmockit测试例子

    It indeed a bad smell, but before you refactor them, you may need to make them testable firstly. Now, jmockit comes to us. "Tests can easily be written that will mock final classes, static methods...

    learning-to-smell-starter-kit

    学习气味-入门套件 :flexed_biceps: 挑战页面: : :speaking_head: 讨论论坛: : :trophy: 页首横幅: : :laptop: 安装git clone ... 这将为您提供类似于以下内容的文件夹结构: .├── data│ ├── test.csv│ ...

    软件测试中单元测试VS私有方法

    软件测试中单元测试VS私有方法软件测试前几天,NareshJain在ManagedChaos上发了篇博客,总结了一些测试中的badsmell。例如:●一个方法中有太多testcase——被测试的方法做了太多事情。●太多的setup/teardown——...

    免费低多边形长剑“B'smell”模型包

    长剑“B'smell” 3D 模型(低多边形)/ 免费低多边形长剑“B'smell”模型。。低多边形 模型全部展开并被贴上纹理,可用的纹理格式为 PNG,包括 1k、2k 和 4k 版本。纹理、材料和网格都有适当的名称。模型已完全贴上...

    J2EE架构数据表示:Struts+Hibernate

    Form Bean是Web层的数据表示,他不能被传递到业务层;PO是持久层的数据表示,在特定... 当然了,理论是一回事,实际操作也不一定非要这样干,你可以自行取舍,在实际项目中灵活一点,增加一点bad smell,提高开发效率。

    软件重构技术中气味检测的序言研究-研究论文

    尽管重构可以应用于任何编程语言,但大多数重构当前工具都是针对Java语言开发的。 本文认为,重构是保持软件可维护性的方法之一,所提出的框架可以在软件开发的早期阶段通过及时的警告来帮助开发人员避免类似的代码...

Global site tag (gtag.js) - Google Analytics