![](https://img-blog.csdnimg.cn/20201014180756916.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
实践中的重构
zhangxzhi
这个作者很懒,什么都没留下…
展开
-
实践中的重构01_一段代码的细调
重构的概念已经为广大的程序员所熟悉。但是还是有很多细节可以注意。 [code="java"] public static String getHiddenEmail(String email, int prefix, int suffix) { // 仅对包含@的email账户进行处理 if (StringUtil.isBlank(email) || !...2010-08-02 22:12:49 · 110 阅读 · 0 评论 -
实践中的重构31_结果类两种实现的比较
在查询接口结果类设计中,有这么一种思路,即把查询的真实结果和结果码组合起来,形成一个结果类,当调用方使用该接口时,先判断结果是否是成功结果,然后进行相应的处理。 一个示例如下: [code="java"]/** * 列表查询结果。 * * 请在处理成功时[ isSuccess() == true; ]才使用查询结果对象。 * * */ public class ...2011-09-13 19:58:06 · 86 阅读 · 0 评论 -
实践中的重构17_表驱动法
代码以及初始的单元测试见 [url]http://zhang-xzhi-xjtu.iteye.com/blog/875986[/url] 由于测试的数量比较多,而且结构相似,因此,才用表驱动法也是一个不错的选择。 [code="java"]/** * 表驱动法。 * */ public class TestUserQueryService2 { /** * 每一个字符...2011-02-22 00:10:39 · 261 阅读 · 0 评论 -
实践中的重构18_不对称的美
一般而言,自然界是以对称为美的。但是,在编程的世界里面,不对称的情况比比皆是,一样的美。 常见的api中有如下例子: [code="java"] // String的方法。 public String substring(int beginIndex, int endIndex) // List的方法。 List subList(int fromIndex, int t...2011-02-26 22:30:20 · 108 阅读 · 0 评论 -
实践中的重构19_脱裤子放屁
每当看到代码中有一个明显的冗余的时候,我就有一个感慨,这家伙时间真多啊,放个屁还要脱裤子。 看例子。 [code="java"] if (addressCode != null && (StringUtil.equals(addressCode, HK) || StringUtil.equals(addressCode, MACAO) || String...2011-03-03 23:17:06 · 377 阅读 · 0 评论 -
实践中的重构20_一段可笑的异常处理逻辑
Code review也是一个充满乐趣的事情,在一次Code review中,发现了如下代码。 [code="java"] try { f(); } catch (RuntimeException e) { throw new RuntimeException(e); }[/code] 百思不得其解啊。为什么要捕捉一个RuntimeException又把它抛出去呢...2011-03-06 20:32:15 · 101 阅读 · 0 评论 -
实践中的重构06_方法调用顺序和性能
大部分的书在讲解涉及到性能优化的时候都告诉我们不要过早优化。简而言之,过早优化是万恶之源。 过早的担心性能问题,不经过性能测试,同时花费大量的时间和精力去在一些主观判断的性能瓶颈点做了一些性能优化的工作,实际上很有可能对性能提高没有什么帮助,而且导致代码可读性直线下降。这样的做法当然是不明智的。 但是,打着过早优化是万恶之源的幌子,从而在写代码的时候压根不考虑性能问题,以为计算机就是万能机器,...2010-11-15 21:50:36 · 101 阅读 · 0 评论 -
实践中的重构07_能不能通过名字猜用途
代码中如果有一行code是这样的, [code="java"]String email=userInfo.getEmail();[/code] 那么我们会对这行代码做出什么样的判断呢? 我对这行代码的判断是从一个用户信息的模型中取出了用户的email。我相信大部分的人和我的猜测应该一致的。我把这个叫做合理猜测。 但是很遗憾,这个猜测是错误的。同事给我指出在数据库中email的字段的存储...2010-11-28 08:26:05 · 61 阅读 · 0 评论 -
实践中的重构08_集合判空时的可读性
代码的可读性应该还是着重强调的,毕竟,代码是给人读的。如 [code="java"]if(null==a)[/code] 这样的代码,看的出是从c惯用法继承下来,试着读一下,当null不为a,则如何如何。至少我读起来有点别扭。我还是喜欢这样的形式,当a不为null,则如何如何。 当然,更厉害的是经常看到如下的片段 [code="java"]if(list.size()==0) if(li...2010-11-28 08:59:36 · 92 阅读 · 0 评论 -
实践中的重构09_多余的防御性编程(new)
众所周知,防御性编程是一个编程的最佳实践。良好的防御性编程,可以增强程序的健壮性,但是没有银弹,最佳实践也有一个适用场景的问题。 试看如下代码: [code="java"] /** * 异常处理接口。 * */ public interface ExceptionHandler { /** * 是否处理该异常。 * */ public boole...2010-12-04 10:36:06 · 76 阅读 · 0 评论 -
实践中的重构28_小心怀疑类库
一般而言,类库的使用频率较高,场景较多,隐藏的bug就较少。 因此,当我们发现代码中有问题的时候,首先应该怀疑应用的代码,只有确定了应用的正确性后,再去排查类库的bug。 [code="java"] Money income = new Money(0); Money outgo = new Money(0); for (Money money...2011-07-24 10:25:20 · 68 阅读 · 0 评论 -
实践中的重构21_给她一个好名字
名字的重要性实在是再怎么强调都不为过的。 为什么名字这么重要呢?我的看法是,构建维护系统过程中最重要的事情之一就是同时建立并维护系统的一致性概念模型。无论通过何种手段进行沟通,如语言,文档,代码,注释,最重要的是有一套沟通的基石。即沟通各方对概念的理解是相同的,当提及一个概念时,大家所指的事物是相同的,没有二义性,没有模糊性。最怕张三在说西瓜,李四以为是个芝麻,鸡同鸭讲。倘若如此,好的结果是沟通...2011-03-20 13:03:52 · 101 阅读 · 0 评论 -
实践中的重构22_不要垃圾
Java引入了GC当然很好,减轻了程序员手工管理内存的负担,但是也不能因为有了GC就毫无顾虑的搞出很多垃圾来。 [code="java"] A a = new A(); if (condition) { a = getAFromSomePlace(); } else { a = getAFromOtherPlace(); }[/code] 上面的代码片段中,...2011-03-20 13:31:05 · 87 阅读 · 0 评论 -
实践中的重构23_详尽的注释未必是好注释
注释一直是软件开发中的一个老大难问题。 代码中一个注释都没有是一种常见情况,给后来的开发维护带来巨大的成本。 代码中注释零零散散也是一种常见情况,这个依赖于程序员,有的程序员自觉的写上注释,有的觉得无所谓,干脆不写,有的在该写的地方写,不该写的地方省略,有的在不该写的地方写,该写的地方留白让后人抓狂。 系统大了,代码多了,公司一般都会出台一些强制性的代码规范,规范中自然少不了注释规范。于是,...2011-03-20 17:37:42 · 779 阅读 · 0 评论 -
实践中的重构29_不自动的自动化测试
测试的精髓之一就是自动化。把一切可以自动化的东西都自动化起来,从而节约宝贵的人力,极大的提高效率。 看一个UnitTest的实现如下: [code="java"] @Test public void test() { Date start = DayUtil.parseDate("20110101"); Date end = DayUtil.parseDate("2011011...2011-07-31 18:00:49 · 102 阅读 · 0 评论 -
实践中的重构27_不要忘了内存空间
方法在设计中,一般关注的是方法的功能契约,即方法需要什么样的参数,方法运行时会保持什么样的不变量,方法运行后会得到什么样的输出。较少会关注到方法的非功能性特征,典型的为方法的执行时间,方法执行时的内存空间消耗等等。 最近关注到一段代码,因为该段代码是导致OutOfMemoryError的一个因素,所以拿来一看。 [code="java"] public enum WorkingDay { ...2011-06-06 18:31:52 · 66 阅读 · 0 评论 -
实践中的重构26_奇怪的接口注释
最近又看到奇怪的注释。 [code="java"] /** * 用户查询服务。 * * * 提供接口 * 1 VIP用户查询服务。 * 2 使用用户名查询用户服务。 * 3 使用id查询用户服务。 * * */ public interface UserQuery { /** * 用户是否是VIP用户? *...原创 2011-06-06 16:10:58 · 85 阅读 · 0 评论 -
实践中的重构10_平铺直叙的代码
很多应用程序的主要目的就是用计算机来代替人处理真实世界中的问题。真实世界和计算机世界之间有着巨大的差异。编程语言,编程方法一直以来都有一个重要的发展方向,提供一个平台,尽量减少这个差异。面向对象语言,面向领域编程,为解决该问题在不同层次提供了解决方案。 在代码级别,也可以通过种种方式减少这个差异。 先看下面一段代码,需求和场景是这样的。 查询用户列表,传入一个整数,指...2010-12-13 21:22:19 · 126 阅读 · 0 评论 -
实践中的重构02_代码的视觉效果 视觉效果就是逻辑
相信程序员都会承认读代码的时间比写代码的时间长。那么写代码的时候有没有什么可以帮助其他程序员包括自己快速读程序的手段呢。 试看一例,当然这里给的日志很简单,实际中对于重要操作,日志是要打很多东西的。 [code="java"] try { // 一个操作,有可能抛出异常 db.operate(); } catch (Exception e) { log.warn...2010-08-29 12:19:21 · 106 阅读 · 0 评论 -
实践中的重构03_批处理方法默认约定
最近看代码的时候,发现了一个奇怪的现象。关于调用批处理接口的问题。 如调用一个查询用户信息的接口为 UserInfo getUserInfo(String id) 则对应的批处理接口为 List getUserInfoByIds(List ids) 很多地方对该返回值进行了校验,即用for循环比对返回的UserInfo进行比对,担心返回的列表的长度和传入参数的长度不同,担心返...2010-09-09 01:08:04 · 82 阅读 · 0 评论 -
实践中的重构04_了解每一行代码 装箱的布尔值(new)
写代码,一定要对自己写的(维护的)每一行代码都进行深入的研究。写程序本来就是一个很细致的活儿,粗心大意和自以为是的猜测都是在给后人或自己挖坑。 简单的一个布尔值装箱,都有可能是bug的根源。 Code review的时候,发现一段代码如下: Boolean isNeedProxy = (Boolean)threadLocalMap.get(ip); return ( isNeedPro...2010-09-10 17:51:15 · 79 阅读 · 0 评论 -
实践中的重构05_简洁的代码
简单的就是美的,这句话大部分时候还是很有道理的。在代码中,有很多的细节是需要程序员留心注意。 [code="java"] if (a || b || c) { return true; } return false;[/code] 这样的代码看起来并不是一个简洁的代码。 [code="java"]return a || b || c;[/code] 一行简单的代码就可...2010-09-13 13:12:26 · 94 阅读 · 0 评论 -
实践中的重构11_茴香豆的多种写法
鲁迅先生的名文孔乙己中,孔乙己纠结于茴香豆的茴字有多种写法,可惜小孩子不愿意学,可惜了孔乙己的一片良苦用心。 一个功能,不同的程序员的实现,基于各种因素,可能是千差万别的。即使是同一个程序员,一般也会有多种方式来完成该程序的编写。面对各种不同的可能实现方式,挑选出适合当前场景的实现,就变成了程序员责无旁贷的任务。 [code="java"] /** * 这个是最早的程序版本,把一个字...2010-12-16 21:35:06 · 182 阅读 · 0 评论 -
实践中的重构12_不要乱用异常
code review的时候,发现了如下代码。 [code="java"] /** * 验证一个字符串是一个长度为10,且内容都是数字。 * */ public static boolean validate(String str) { if (str == null || str.length() != 10) { return false; } ...2010-12-30 00:36:40 · 91 阅读 · 0 评论 -
实践中的重构13_利用递归提高代码的可维护性
有这么一段代码,是用来解析国内的地址信息的。 AddressInfo对象唯一确定一个地址信息,该地址信息可以是省市区县任意一级的地址信息,省级地址为市级地址的父地址,市级地址是区县地址的父地址。AddressInfo对象里面存储了父地址的地址码,当地址码为null或者查找不到该地址码对应的地址时,认为该AddressInfo对象为省级地址。系统提供了查找一个地址码对应父地址的方法,。 [cod...2010-12-30 01:38:21 · 91 阅读 · 0 评论 -
实践中的重构14_用方法设计保证正确性
一般来说,方法的调用方遵循方法的契约调用某方法来完成某功能。每个方法的功能应该是相互独立而语义清晰的。好的代码必然是清晰的,但是清晰的代码未必是好的。 方法存在的目的是被调用方调用,因此,从调用方的角度来看,清晰的方法一样会存在一些潜在的问题。 下面的代码中,Helper提供了2个方法,一个用来转换对象,一个对来验证对象。看上去很清晰很好。 [code="java"] class Helpe...2011-01-04 21:40:09 · 132 阅读 · 0 评论 -
实践中的重构15_null的意义和集合类作为方法结果类型
在编程中,估计null应该是一个很常写的词汇了。 实践中,经常看到大量类似user!=null或者userList!=null的检测。当然,这么做是为了防止NullPointerException。问题是,null这么常见,它究竟是什么意思。 观察如下一段code: [code="java"] String userName = "allen"; User user = userSe...2011-01-12 22:16:59 · 111 阅读 · 0 评论 -
实践中的重构16_多即是少
在编写UT的过程中,随处可见重复,硬编码等等使得代码僵化的代码。 UT也是代码,并且其重要性和产品代码相比,只高不低。 以下是一段产品代码的框架。 [code="java"]public interface UserQueryManager { /** * 获得历史库和生产库的分界时间点。 * */ public Date getHisDate(); /** ...2011-01-16 23:44:53 · 140 阅读 · 0 评论 -
实践中的重构24_持续的方法重构
很少有人可以一遍就写出好的代码。写代码和写文章差不多,大部分人不是天才,需要的是不断的修改,才能使之演化为一段不错的代码。同时,即使是一段原本还算不错的代码,随着时间的推移,受到诸如需求变更,缺陷修复,后期维护等因素的影响,如果不是特别注意的话,也会使其慢慢腐烂。我们能做的,就是持续重构。 以下是一个例子。 原有的代码如下: [code="java"]public interface Dat...2011-05-01 02:20:00 · 130 阅读 · 0 评论 -
实践中的重构25_UT也需要持续重构
UT是个好东西,在对代码进行持续重构的过程中,UT可以保证代码的正确性。同时,和产品代码一样,UT也是需要不断重构的。 有一个接口,原始定义和对应的UT如下: [code="java"] /** * 构建一个按照自然周排好的日期列表(包括最近30天,不包含当日),周时间距离现在越近,在列表中越靠前。 * * * 保证每个子列表的大小都为7(一个星期的天数),没有日期...2011-05-01 11:20:40 · 114 阅读 · 0 评论 -
实践中的重构30_不做油漆匠
油漆匠的故事是编程文化中的一个著名故事。本地化如下。 小强毕业后得到一份街道办油漆匠的工作,工作内容是在马路中间喷涂油漆画线。上班第一天,他拿出一罐环保漆来到他负责的路段,喷涂了300米长的线。“小伙子很给力啊!”街道办徐大妈称赞道,然后给了他300大洋作为工钱。第二天,小强只喷涂了150米。“是不是昨晚没有睡好啊。算了,还是比原来的老王头麻利多了,还是小伙子干活又好又快啊。”徐大妈又掏了150...2011-08-15 23:42:57 · 163 阅读 · 0 评论 -
实践中的重构32_使用标准的IO操作写法。
看到这样一段代码,功能为读取一个指定文件的内容然后返回。 [code="java"] private String parseContent(String filePath) { StringBuffer sb = new StringBuffer(); BufferedReader reader = null; String tempLine = null; t...2012-07-14 18:42:41 · 82 阅读 · 0 评论