译者按:

近来想深入了解下 Java 流底层的实现机制,于是搜索各种资源,最后发现 Martin Fowler 发表的一篇关于集合管道模式的一篇文章,有幸得以拜读,关于集合管道有其独到的见解,看过之后深感佩服,由于原文是英文,索性将其翻译,和大家一起分享,翻译不合理的地方敬请指出。

集合管道

集合管道是一种编程模式,将一些计算转化为一系列操作,通常情况下每个操作的输出结果是一个集合,同时该结果作为下一个操作的输入,常见的操作主要有filter、map和reduce。这种模式常见于函数式编程语言中,因为有了lambdas,这种模式在面向对象语言中也很常见。如果你不熟悉这种模式,通过本文关于构造管道事例的讲解,你会理解其核心概念,从一种语言联想到另外一种语言。

在软件中,集合管道是一种最常见、最令人酣畅淋漓的模式。在 unix 黒与白的命令行中,在面向对象设计语言万物皆对象的类中,在函数式编程语言第一等公民的函数中,都可以发现它们的身影。 不同环境有着不同的表现形式,共通操作有着不同的名称,但是一旦你熟悉了它,你会发现根本离不开它。

初见

第一次接触到这种模式,应该是使用 Unix 的时候。接下来会介绍一些 Unix 的事例,设想下如何在 bliki/entries 目录下查找文件内容包含文本 "nosql" 的文件列表,可以使用grep这样操作:

grep -l 'nosql' bliki/entries

每个文件出现单词 "nosql" 的次数:

grep -l 'nosql' bliki/entries/* | xargs wc -w

根据次数排序:

grep -l 'nosql' bliki/entries/* | xargs wc -w | sort -nr

排序后取top3:

grep -l 'nosql' bliki/entries/* | xargs wc -w | sort -nr | head -4 | tail -3

不管之前还是以后,和其他环境的命令行工具相比,这种方式都是无可比拟的。

在开始使用Smalltalk时,发现了相同的模式。 假设有一个文章列表 someArticles,列表中的每篇文章 article 定义了很多标签,同时又统计了单词数量,如果想查找哪些文章包含标签 "nosql":

someArticles select: [ :each | each tags includes: #nosql]

其中 select 方法使用了Lambda表达式来定义:每篇文章 article 作为输入参数,同时验证标签集合中是否包含 "nosql"。该方法会作用于文章列表的每篇文章,最后输出匹配的结果。

为了排序,扩展了上面的代码:

(someArticles

select: [ :each | each tags includes: #nosql])

sortBy: [:a :b | a words > b words]

sortBy 方法同样使用了Lambda表达式定义:文章互相比较,最终返回一个排序后的文章列表。继续其他操作:

((someArticles

select: [ :each | each tags includes: #nosql])

sortBy: [:a :b | a words > b words])

copyFrom: 1 to: 3

与 unix 管道最核心的相似之处在于:涉及的所有操作例如 select、sortBy 和 copyFrom 输入输出都是集合。unix 中集合是一行行记录构成的流,而Smalltalk集合是对象,但基本概念是相同的。

最近,使用Ruby进行了很多开发,改进后的语法可以更加便捷的操作管道。

some_articles

.select{|a| a.tags.include?(:nosql)}

.sort_by{|a| a.words}

.take(3)

在面向对象语言中,使用方法链构造集合管道是一种很自然的方式。同样也可以使用嵌套函数。

回顾一些基础知识,看看如何使用 lisp 构造类似管道,我会定义存储所有文章的结构体 articles:其中可以通过方法 article-words 和 article-tags 获取内部字段。

基于现有的文章列表 some-articles,获取标签集合中包含 nosql 的文章:

(remove-if-not

(lambda (x) (member 'nosql (article-tags x)))

(some-articles))

为了排序,再次使用了lambda:

(sort

(remove-if-not

(lambda (x) (member 'nosql (article-tags x)))

(some-articles))

(lambda (a b) (> (article-words a) (article-words b))))

使用方法 subseq 获取top3:

(subseq

(sort

(remove-if-not

(lambda (x) (member 'nosql (article-tags x)))

(some-articles))

(lambda (a b) (> (article-words a) (article-words b))))

0 3)

看啊,那就是管道,通过我们一步步的构造,看起来是多么完美。然而最终的表达式是否清晰自然,有待商讨。对于 unix、smalltalk 和 ruby 下管道执行的顺序依赖于内部方法的线性排序。 在你的头脑中应该很容易虚拟化这种场景:左上角的数据经过过滤,最后从右下角输出。 同样可以在 Lisp 中使用嵌套函数,但是你需要掌控函数的嵌套层级。

最近流行的 lisp,Clojure 避免了嵌套层级:

(->> (articles)

(filter #(some #{:nosql} (:tags %)))

(sort-by :words >)

(take 3))

符号 "->>" 是一个线程宏,通过使用 lisp 强大的语法宏功能将每个表达式结果作为下一个表达式的输入。 你可以使用提供的库将嵌套函数转化为线性管道,只需要遵循约定即可。

对于大多数函数开发者来说,可以游刃有余的处理函数的嵌套,线性化无足轻重,所以这就是为什么经过了这么长的时间,lisp才支持操作符 "->>" 。

这些天常听到函粉对于集合管道的赞赏之声,夸奖函数式编程语言的强大,而又感叹面向对象设计语言的不足。这种说法其实非常片面,因为对于众多的 Smalltalk 开发者来说已经广泛的使用了集合管道。而集合管道在面向对象语言中例如 C++、Java 和 C# 中没有被支持的原因,有人说没有借鉴 Smalltalk 的 lambda,此外缺少足够丰富的集合操作。以至于很多面向对象开发人员栽进了集合管道里。 Java 大行其道时不支持lambdas,对于像我这样 Smalltalk 开发者常常会抱怨,但是又不得不忍受。 在 Java 中如何构造集合管道,有过各种尝试,而每种尝试都需要大量的代码来实现,使得即使技术熟练的人也被迫放弃。 在2000年左右我开始使用Ruby,重要原因是因为Ruby支持集合管道。有时候我会感概在我的 Smalltalk 时代,错过了很多有价值的东西。

lambdas 由于短小实用赢得了很多关注,C# 已经支持很多年,现在 Java 也开始支持。 如今你可以在许多语言中使用集合管道。

lisp钢管_技术专栏集合管道模式(上)相关推荐

  1. lisp钢管_图纸管道材料代号说明

    - - - - - - - (LL) 空格 空格 空格 长度 - - - 空格 - - - 空格 空格 - - - - 空格 空格 - - 空格 隔环 - 空格 - 空格 - - - - 空格 空格 ...

  2. lisp钢管_(最全的)管道材料代号说明

    - - - - - - - (LL) 空格 空格 空格 长度 - - - 空格 - - - 空格 空格 - - - - 空格 空格 - - 空格 隔环 - 空格 - 空格 - - - - 空格 空格 ...

  3. 图像缩放算法_技术专栏|基于无人机LK光流算法的适用性及其优化方法探究

    点击上方蓝字关注我们 问题描述 ◆ ◆ ◆ 一般的LK光流算法存在一个比较明显的局限性.我们知道,一般的LK光流算法必须包含三个假设: (1)亮度恒定: (2)时间连续或者运动是小运动: (3)空间一 ...

  4. 有机晶体数据库_技术专栏:一篇文章搞懂晶体学信息文件CIF及其获取方法

    [引语]材料人现在设立各种文章专栏,所涉及领域正在慢慢完善,由此也需要更多的专栏作者,没错,我们正在招兵买马,期待你们的加入,有意向的小伙伴可直接联系cailiaorenVIP.不要再犹豫,下一个专栏 ...

  5. python库读取cif文件_技术专栏:一篇文章搞懂晶体学信息文件CIF及其获取方法

    [引语]材料人现在设立各种文章专栏,所涉及领域正在慢慢完善,由此也需要更多的专栏作者,没错,我们正在招兵买马,期待你们的加入,有意向的小伙伴可直接联系cailiaorenVIP.不要再犹豫,下一个专栏 ...

  6. vue 大数据 渲染_技术专栏 | DMap——实战Vue百万条数据渲染表格组件开发

    作者:TalkingData 李志刚 本文由TalkingData原创,转载请获取授权. 李志刚:近几个月在开发一个基于Vue的数据可视化分析辅助应用---DMap(谛听),一套为数据分析师和数据科学 ...

  7. yum命令 启用仓库_技术|如何列出在 Linux 上已启用/激活的仓库

    有很多方法可以列出在 Linux 已启用的仓库.我们将在下面展示给你列出已激活仓库的简便方法.这有助于你知晓你的系统上都启用了哪些仓库.一旦你掌握了这些信息,你就可以添加任何之前还没有准备启用的仓库了 ...

  8. 文件表单带数据一起提交spring_基于 Spring 实现管道模式的最佳实践

    管道模式(Pipeline Pattern) 是 责任链模式(Chain of Responsibility Pattern) 的常用变体之一.在管道模式中,管道扮演着流水线的角色,将数据传递到一个加 ...

  9. 基于 Spring 实现管道模式的最佳实践

    本篇为设计模式第二篇,第一篇可见设计模式最佳套路 -- 愉快地使用策略模式 管道模式(Pipeline Pattern) 是责任链模式(Chain of Responsibility Pattern) ...

最新文章

  1. 在阿里干了5年招聘,这10条建议我必须分享给你!
  2. 同盟与对抗:谈《少女杜拉的故事》中的治疗关系(转)
  3. python查看CNN训练模型参数
  4. Effective Modern C++ 第三章第二节,C++新特性
  5. 任意给定一个正整数N,求一个最小的正整数M(M1),使得N*M的十进制表示形式里只含有1和0。...
  6. PHP对自己I/O流访问的封装(转)
  7. 苹果6可以分屏吗_苹果可以5g网络吗
  8. android悬浮控件-仿360手机助手应用详情页
  9. 老司机 iOS 周报 #37 | 2018-09-24
  10. Hazelcast IMDG参考中文版手册-第五章-集群设置
  11. xorg方式在无图形环境安装oracle,告别静默安装
  12. Codeforces Round #657 (Div. 2) B题 Dubious Cyrpto
  13. 马云退隐前,在年会上说了最重要的三件事
  14. 机器视觉学习资料了解
  15. 2022 年顶级商业和 IT 认证课程,让你获得职业信誉,提升竞争力
  16. 【go get】下载的包放在哪里了?
  17. win10家庭版怎么开启Administrator超级管理员帐户
  18. 不能bostype没有元数据异常_金蝶EAS_BOS工作笔记
  19. 【翻译】如果软件工程需求旺盛,但为什么找一份软件工程工作这么难?
  20. 【人工智能行业大师访谈】1. 吴恩达采访 Yoshua Bengio

热门文章

  1. win 二进制门安装mysql_PG二进制包编译Windows下mysql_fdw
  2. 纵观计算机网络发展历程,人工智能在计算机网络技术中的应用分析
  3. html绘制静态图表,怎样用JavaScript和HTML5 Canvas绘制图表
  4. html object标签与java,html之object标签的classid收集
  5. 帝国cms熊掌号MIP主动推送教程
  6. Azure PowerShell (9) 使用PowerShell导出订阅下所有的Azure VM的Public IP和Private IP
  7. 如何在Ubuntu中修改默认程序
  8. form data和request payload的区别
  9. iOS开发之UIApplication
  10. 4.[attribute!=value]属性选择器