BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

代码之丑(十四)--多个构造函数

| 作者 郑晔 关注 2 他的粉丝 发布于 2012年7月5日. 估计阅读时间: 3 分钟 | CNUTCon 了解国内外一线大厂50+智能运维最新实践案例。

代码评审,我对一个TreeSet产生了兴趣。

TreeSet<String> configuration = new TreeSet(); ... Handler handler = new Handler(configuration); 

“为什么要用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)关注我们,并与我们的编辑和其他读者朋友交流。

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

一目了然的命名就是简单! by 高 翌翔

当遇到多构造函数或重载方法时,确实难以做到一目了然,
因为需要通过参数的数量及其排列顺序来判断各个同名方法的功能,

重载越多、参数越多,当然也就越痛苦(想想Excel的COM接口,你懂的)!

其实,多构造函数或重载方法是一种重复,即名称重复,而且这种重复不利于编写、阅读、维护代码,
因此就要消除重复,把它们变成不同的命名,直到大家都能一目了然为止!

莫名其妙的文章。 by z x

对于多函数合并参数类型不同的最好的方法是采用 函数的泛型类型约束,编写泛型函数。

这和构造函数有什么关系,这文章完全扯淡。

很多时候需要用完全不同数量和类型的参数进行初始化,一个构造函数可以解决吗?

Re: 莫名其妙的文章。 by luo xiaoyong

我也觉得这里不是构造函数的问题, “代码之丑” 跟这里的构造函数没什么直接关系。

不过作者这里举出来的例子的确是个问题, 代码实现上是有点怪。 的确没必要分别通过TreeSet<String>, HashSet<String>两种方式来构造。

作者通过一个工厂进行了改进, 只需要通过Set<String>, 。。。

但是我觉得只需要用一个Set<String>来构造就行了, 构造函数内部实现根据Set<String>的configuration来进行不同的对象构造。 至于是否有必要再搞个工厂, 个人有个人的想法了, 作者通过两个不同的工厂方法来分别对两种情况的对象构造, 就如文章中所说, 程序代码理解上更友好了。。。。</string></string></string></string></string>

能一目了然的做法是更好的选择 by Minghang Chen

泛型构造函数的问题在于,用泛型来区分业务逻辑,对可读性及维护性都不够友好。

这个不是构造函数的问题 by cui weifu

我理解,这个是因为一个方法干了两件不同的事情导致的“丑”。即便不是构造函数,是其他的别的函数这么用也是不好的。
构造函数作用在于构造,更多的是用来设置对象默认值。

Re: 一目了然的命名就是简单! by cui weifu

是用重载还是是新起个名称,这个是方法的功能决定的, 如果某方法调用时是传递不同的数据,那么对默认数据的重载是非常适合的。

这篇文章确实不怎么样。 by Victor Kevin

1)工厂方法作用是使用者(客户端)隐藏复杂的对象构建过程
2)Handler用HashSet作为参数类型根本就是违反“迪米拉法规",况且面向对象应多使用依赖倒转,这里应以Set接口类型为参数。

Re: 这篇文章确实不怎么样。 by Wong Peter

代码之丑是指把丑的代码改的更丑?!

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

8 讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT