代码评审,我对一个 TreeSet 产生了兴趣。
TreeSet<String> configuration = new TreeSet<string>(); ... Handler handler = new Handler(configuration); </string>
“为什么要用 TreeSet 呢?”,我问道。
“因为这是构造函数的参数决定的。”,有人回答。
“可以打开源码看一下吗?”,对于这种处理,通常人们都会选择 HashSet,好奇心驱使我要进一步专研一下这段代码。
我看到了这个构造函数的声明:
public Handler(TreeSet<String> configuration) { ... }
在我开始研究这个构造函数使用 TreeSet 的缘由之前,我看到了另外一个构造函数,或许它更能满足我的心理需求:
public Handler(HashSet<String> configuration) { ... }
“为什么会有一个用到 HashSet 构造函数?它和用到 TreeSet 的有什么不同”,我继续追问。
“它们是分别处理两种情况的,在不同的配置下起作用。”
我终于知道为什么会有 TreeSet,因为 HashSet 已经被人用了,为了支持另外一种情形,TreeSet 被人从墙角了挖了出来。可是如果不深究代码,谁又能知道这其中的奥妙呢?显然,我们需要一个更具表达力的写法。
之所以陷入这样的坑,根源在于构造函数,因为构造函数只能有一个名字。其实,这里只是要解决构造的问题,而面对这个问题,解决方式几乎再直白不过了:工厂方法。
class HandlerFactory { public static Handler createTrivialHandler(Set<String> configuration) { ... } public static Handler createFancyHandler(Set<String> configuration) { ... } }
这里,用两个名字上有更明确意义的函数替代之前的那两个需要强大理解力的构造函数。当然,这里的参数用了 Set,连具体的类型都省了,真正的面向接口编程。
事实上,如果一个类有多于一个的构造函数,都是值得考虑的。我曾写过一篇《构造函数沉思录》专门讨论这个问题。
作者简介
郑晔,ThoughtWorks 公司首席咨询师,拥有十多年企业级软件开发经验,热衷于探索各种程序设计语言在真实软件开发中所能发挥的威力,致力于探寻合理的软件开发方式,加入ThoughtWorks 公司后,投入到敏捷开发方法的实践之中,为其他公司提供敏捷开发方法方面的咨询服务。他的blog 是梦想风暴,其微博是 @dreamhead 。
查看原文:代码之丑(十四)
感谢张凯峰对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。
评论