BT

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

代码之丑(十三)–封装代替嵌套容器

| 作者 郑晔 关注 2 他的粉丝 发布于 2012年6月27日. 估计阅读时间: 3 分钟 | Google、Facebook、Pinterest、阿里、腾讯 等顶尖技术团队的上百个可供参考的架构实例!

第一次见到这样的代码时,我的第一感觉是,它真复杂:

List<Map<String, String>> configurations;

可只要理性稍一回归,便不难察觉,它少东西了。少什么了呢?

看看这段代码如何使用,下面是一个缩略的版本:

for (Map<String, String> configuration : configurations) {
  for (Map.Entry<String, String> entry : configuration.entrySet()) {
    System.out.println(entry.getKey() + " " + entry.getValue());
  }
}

说白了很简单,其实就是要拿到存在Map里的键值对。在面向对象的程序语言中,有一种神奇的构造,叫做类,而它有一个很重要的特点叫做封装。是的,这段代码少了类,少了封装。闲言少叙,封装起来:

public class ConfigurationItem {
  private String name;
  private String value;
  ...
}

于是,那个容器嵌套容器的声明变成了

List<ConfigurationItem> configurations;

有了类,有了封装,我们就可以再进一步进行封装,比如前面那段代码里的

entry.getKey() + " " + entry.getValue()

实际上,可能只是为了得到这一项的字符串表示而已,那就不如直接提供一个方法:

public class ConfigurationItem {
  ...
  @Override
  public String toString() {
    return name + " " + value;
  }
}

于是,前面那个双重for循环就变化了:

  for (ConfigurationItem item : configurationItems) {
    System.out.println(item);
  }

单以丑陋而言,这段代码还算不上此类的极致,三五层嵌套也是有的,如果某些貌似负责的程序员再给每层取值都加上非空判定,那场面可是相当壮观的。

当容器开始嵌套容器,请考虑封装。

作者简介

郑晔,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 Zhang Gavin

说的不错

这事也不能滥用 by aoch ant

那段代码,我只在某个场景里用一次,也封装个类?
封装有个用途是复用,封装不是为了好看

动不动就弄个类,就为了好看?

写代码确实需要讲究简介美观,但简洁美观与逻辑的严谨比起来,就次要了,加上非空判定怎么就是“貌似负责”了?

咋感觉这个例子举错了? by 林 大海

List<Map><String, String>> configurations;
这是个List中包含Map,换成实际场景的话,可能是个二维数据结果集:List代表行,Map代表列值。
configurations.get(0).get("name"); //得到第一行的name字段的值
configurations.get(1).get("age"); //得到第二行的age字段的值


List<ConfigurationItem> configurations;
public class ConfigurationItem { private String name; private String value;}
这种情况下,只能表示一组 name:value 对,跟二维数据结果集差距不是一般的大吧?</configurationitem></string,>

还是不错的,其实还是分场景 by Dong Stanley

如果是简单用一下的情况怎么简洁怎么写也是没问题的~
封装类有封装类的好处,代码严谨,可读性更好,性能更高一些
就文章举的例子来说,在大数据量的情景下,封装效率会更高

没有上下文,不算个好示例 by Kraft Bai

我有些疑问,如果有这样一个东西,其实往往是在configuration类里面的,难道还要再套一层;如果不是在configuration类里面,那就很有可能不复杂,也不必单独再套个类。
希望作者在给出示例时,代码最好给多点,从现实中拈出,而不是按照自己的想法造出来。

这个系列的文章很苦逼 by Zeng Abrams

这个系列的文章几乎每个我都看过,看到这里确实看不下去了。每次都是站在一个观点上对另外一个狂批,从来不会分析两者各自的优劣。而且,这次这个例子举还错了。Map和ConfigurationItem(key,value)如何类比,应该是和ConfigurationItem(attr1,attr2,attr3...)才可以类比

这个例子列举的不好 by Lee sky

根本没有说到问题的关键上, 而且很容易误导别人也这么去做, 劝一下还是重新写一下再发出来吧, 要对关注的人负责阿

最后那个 foreach 也封装起来吧! by 高 翌翔

各种反复出现的固定结构也应该封装起来,与其视而不见,不如干脆让它消失 :D
例如:foreach、if...then、try...catch...finally等结构。

Re: 咋感觉这个例子举错了? by 邵 俊杰

如果是行列的关系,ConfigurationItem就需要把map中的key的全集定义出来,一个ConfigurationItem对象就表示一行数据

Re: 这个系列的文章很苦逼 by Black Nile

作者也说了,这个是个活生生的例子。
的确,在项目中遇到这样的代码会比较难看。当然在文中的例子中的,不需要封装一个类,apache组织下就已经有人帮你考虑好了。拿来用就行了。

Re: 这事也不能滥用 by 余 昭辉

我不认为这段代码如果只用一次就不封装这样的观点。
这里的List<Map><String, String>> 里面的Map<String, String>本就表示一个“配置项”, 这里缺少一个领域概念。所以创建一个类来表示这个领域概念是再合适不过的,项目的可维护性和可读性就是这样很多的领域概念积累起来的。

比如我们系统中经常传递一个Date from, Date to,那我们就提取一个DateRange的概念。即使现在只用一次又何妨。</string,></string,>

Re: 咋感觉这个例子举错了? by 余 昭辉

人家已经列出这个List<Map><String, String>> 的使用场景了.....</string,>

Re: 没有上下文,不算个好示例 by zhao hongwei

同意,如果在hash查找的时候怎么办?

Re: 这事也不能滥用 by 谢 之磊

顶一下。从长远来看,你怎么知道这段代码只用一次呢?如果你新接手项目代码包含一堆的:
for (Map<String, String> configuration : configurations) {
for (Map.Entry<String, String> entry : configuration.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
}
for (Map<String, String> configuration : configurations) {
for (Map.Entry<String, String> entry : configuration.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
}
你有什么感觉呢?
我第一眼就觉得这样的代码很亲切、很舒服,哪怕它多了一个类:
for (ConfigurationItem item : configurationItems) {
System.out.println(item);
}
public class ConfigurationItem {
...
@Override
public String toString() {
return name + " " + value;
}
}
</string,></string,></string,></string,>

Re: 咋感觉这个例子举错了? by yp wang

说的没错,这个例子误人子弟。

有误导之嫌 by Yang Lifan

为何改了之后循环层数少了?因为 List<ConfigurationItem> 只是和 Map 所对应的,硬生生把原来的层级关系搞掉了一层

允许的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通知我

16 讨论

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


找回密码....

Follow

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

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

Like

内容自由定制

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

Notifications

获取更新

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

BT