java 示例_功能Java示例 第2部分–讲故事

java 示例

这是称为“ Functional Java by Example”的系列文章的第2部分。

我在本系列的每个部分中开发的示例是某种“提要处理程序”,用于处理文档。 在上一部分中,我从一些原始代码开始,并应用了一些重构来描述“什么”而不是“如何”。

为了帮助代码向前发展,我们需要先讲一个故事 。 这就是这个部分的来历。

如果您是第一次来这里,最好从头开始阅读。 它有助于了解我们从何处开始以及如何在整个系列中继续前进。

这些都是这些部分:

  • 第1部分–从命令式到声明式
  • 第2部分–讲故事
  • 第3部分–不要使用异常来控制流程
  • 第4部分–首选不变性
  • 第5部分–将I / O移到外部
  • 第6部分–用作参数
  • 第7部分–将失败也视为数据
  • 第8部分–更多纯函数

我将在每篇文章发表时更新链接。 如果您通过内容联合组织来阅读本文,请查看我博客上的原始文章。

每次代码也被推送到这个GitHub项目 。

作为参考,我们现在以以下代码为起点:

class FeedHandler {Webservice webserviceDocumentDb documentDbvoid handle(List<Doc> changes) {changes.findAll { doc -> doc.type == 'important' }.each { doc ->try {def resource = webservice.create(doc)doc.apiId = resource.iddoc.status = 'processed'} catch (e) {doc.status = 'failed'doc.error = e.message}documentDb.update(doc)}}
}

大声读出

当我最初开始使用Spock作为测试框架时,由于它是多年前Grails默认提供的,因此它的众多功能和易用性给我留下了深刻的印象(至今仍是)。

你知道什么是假人,存根和间谍吧? Mockito拥有它们,Powermock拥有它们以及基本上所有其他严肃的(单元)测试框架。 Mock的概念并不难掌握(您可以在此处阅读全部内容),但是Spock具有一种特殊的方式来描述其(与预期的)模拟交互。

关于“基于交互的测试”的一章非常出色,它解释了如何使用代码示例来记录这些交互。

“模拟”子章开头为:

模拟是描述(强制)规范下的对象与其协作者之间的交互的行为。 这是一个例子:

def "should send messages to all subscribers"() {when:publisher.send("hello")then:1 * subscriber.receive("hello")1 * subscriber2.receive("hello")
}

如果您不熟悉Spock,Groovy或仅仅具有上述写作风格,请不要担心!

Spock上面的文档的作者也认识到,并不是每个人都会立即理解这里发生的事情。

他们会提供一些建议,并继续提供文档:

大声读出 :“当发布者发送“ hello”消息时,两个订户都应该只收到一次该消息。”

我对“大声朗读”的重视是我的,因为我认为这很重要。 这里不讨论Spock的更多细节,而是我自己在日常编码中要牢记的建议本身。

  • 当我编写一段代码时,我可以大声读出吗?
  • 当其他人读取我的代码时,他/她可以大声读出吗?

这里的“大声” 与音量无关,而是可以用一种简洁易懂的方式描述“这里正在发生什么”。 这使得对代码的推理变得容易。

高级别与低级别

请考虑以下情形:

在不知名的城市中开车游览了几个小时以找到剧院后,汽车导航系统出现故障后,您最终决定停下来询问方向。

您在行人附近停下。

您:

先生,您碰巧知道如何从这里到达剧院

行人:

  1. 当然,这很容易。 开始了:

  2. 检查窗户以确保您具有良好的可见性。 检查后视镜以确保它们正确对齐,从而为您提供正确的道路视野。

  3. 调整座椅,使双脚舒适地到达两个踏板。

  4. 关闭视窗。

  5. 重置转向信号灯。

  6. 开始驾驶前,请松开驻车制动器。

  7. 啊,我看你有自动档。 请把变速杆放在“驱动器”中。

  8. 慢慢踩刹车,并监控仪表盘仪表。

  9. 继续前进,提高速度,监控车速表,将RPM保持在2000附近

  10. 大约120码后,在开始转向左车道之前,请先与您的方向灯指示至少两秒钟。

  11. 缓慢将汽车移至另一车道。 稍微将您的手放在方向盘上,以改变车道。 车轮只需要很小的移动即可; 因为大多数现代汽车都装有动力转向系统。 更改车道大约需要一到三秒钟。 减少一点,您做得太快了; 再也没有,你做得太慢了。

  12. 再走X步…

  13. 祝好运!

或者,考虑对话将像这样的替代宇宙:

您:

先生,您是否会知道如何从这里到达剧院?

行人:

  1. 当然,这很容易。 开始了:

  2. 左转,过桥。 在你的右边。

  3. 祝好运!

最后一种情况是轻而易举:明确指示要做什么和去哪里!

但是,第一种情况是细节缠身 -有关驾驶汽车本身的低级细节 -即使我们不希望在现实生活中得到这样的指导,我们仍然会编写这样的软件。

告诉我一些正确的内容。 如果我需要具体信息,我会要求它。

(顺便说一句wikihow.com:如何驾驶汽车,请捐赠上述说明中的一些。如果您确实需要学习驾驶,它有很多资源!)

在正确的级别上讲内容,不仅意味着使用正确命名的类和方法,而且还意味着在其中使用正确的抽象类型

让我们再次看一下我们的代码:

class FeedHandler {Webservice webserviceDocumentDb documentDbvoid handle(List<Doc> changes) {changes.findAll { doc -> doc.type == 'important' }.each { doc ->try {def resource = webservice.create(doc)doc.apiId = resource.iddoc.status = 'processed'} catch (e) {doc.status = 'failed'doc.error = e.message}documentDb.update(doc)}}
}

故事

我们如何在代码中结合“大声读出”和“高级还是低级”?

我们的单handle方法当前显示为什么样?

  1. 查找type -property等于字符串"important"所有文档。

  2. 呼叫createwebservice与文档,返回的资源。

  3. 如果我们有资源,请将资源的id分配给文档的apiId属性。

  4. 将文档的status属性设置为字符串"processed"

  5. 如果发生异常,请将文档的status属性设置为字符串"failed" 将文档的status属性设置为来自异常的message

  6. 最后,使用documentDb在documentDb上调用update

基本上,这只是重复代码语句!

什么故事,我想告诉取而代之的,是以下情况:

  1. 通过Web服务“创建资源”来处理“重要”文档。

  2. 每次成功时,将两者关联在一起并“将文档标记为已处理”,否则将其标记为“失败”。

读得很好,你不觉得吗?

实际上,我们可以通过在IDE中使用几种“提取方法”重构并为提取的方法选择一些好的名称来实现这一目标。

上面故事中用双引号引起的短语是我想在高层看到的重要部分。

“重要”

我为什么要关心文档使用什么属性来确定其重要性? 现在是字符串"important" ,它表示“嘿,我很重要!” 但是如果条件变得更加复杂怎么办?

doc.type == 'important'提取到其自身的方法isImportant

changes.findAll { doc -> isImportant(doc) }// ...private boolean isImportant(doc) {doc.type == 'important'}

“创造资源”

为什么我在这里关心如何在Web服务中调用什么方法? 我只想创建一个资源。

将与Web服务的所有处理都提取到它自己的方法(称为createResource

def resource = createResource(doc)// ...private Resource createResource(doc) {webservice.create(doc)}

“更新为已处理”

提取将资源/文档/将状态设置为其自己的方法(称为updateToProcessed

updateToProcessed(doc, resource)// ...private void updateToProcessed(doc, resource) {doc.apiId = resource.iddoc.status = 'processed'}

“更新失败”

不在乎细节。 提取到updateToFailed

updateToFailed(doc, e)// ...private void updateToFailed(doc, e) {doc.status = 'failed'doc.error = e.message}

似乎我们最后只剩下了documentDb.update(doc)

这是在数据库中存储已处理/失败文档的一部分,我已经在最高级别上进行了描述。

我将其放在每个刚刚创建的updateTo*方法中-一个较低的级别。

private void updateToProcessed(doc, resource) {doc.apiId = resource.iddoc.status = 'processed'documentDb.update(doc)}private void updateToFailed(doc, e) {doc.status = 'failed'doc.error = e.messagedocumentDb.update(doc)}

那么,提取出细节之后,有什么变化?

void handle(List<Doc> changes) {changes.findAll { doc -> isImportant(doc) }.each { doc ->try {def resource = createResource(doc)updateToProcessed(doc, resource)} catch (e) {updateToFailed(doc, e)}}}

任何人(例如,同事,您未来的自我)都会“一口气”地读一读,将了解30,000英尺的行程。

如果您需要任何这些步骤的详细信息,只需深入了解该方法即可。

能够写声明式的东西(本系列的前一部分)并在正确的水平上讲故事(本部分)还将有助于在第3部分及以后的部分中更轻松地进行将来的更改。

现在就这样

作为参考,这是重构代码的完整版本。

class FeedHandler {Webservice webserviceDocumentDb documentDbvoid handle(List<Doc> changes) {changes.findAll { doc -> isImportant(doc) }.each { doc ->try {def resource = createResource(doc)updateToProcessed(doc, resource)} catch (e) {updateToFailed(doc, e)}}}private Resource createResource(doc) {webservice.create(doc)}private boolean isImportant(doc) {doc.type == 'important'}private void updateToProcessed(doc, resource) {doc.apiId = resource.iddoc.status = 'processed'documentDb.update(doc)}private void updateToFailed(doc, e) {doc.status = 'failed'doc.error = e.messagedocumentDb.update(doc)}}

翻译自: https://www.javacodegeeks.com/2017/11/functional-java-example-part-2-tell-story.html

java 示例

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/334370.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python range函数范围_Python range函数

Python range函数教程 range函数详解 语法 range(start, stop[, step]) 参数 参数 描述 start 计数从 start 开始。默认是从 0 开始。 stop 计数到 stop 结束&#xff0c;但不包括 stop。 step 步长&#xff0c;默认为1&#xff0c;可以支持负数。 返回值 返回生成的序列。 案例…

openpyxl删除添加excel列_Python | 如何使用Python操作Excel(二)

0 前言在阅读本文之前&#xff0c;请确保您已满足或可能满足一下条件&#xff1a;请确保您具备基本的Python编程能力。请确保您会使用Excel。请确保您的电脑已经安装好Python且pip可用。请确保您已经读过前文&#xff1a;如何使用Python操作Excel(一)LogicPanda&#xff0c;公众…

payara 创建 集群_使用Payara Micro的Easy Java EE Microservices

payara 创建 集群想知道如何开始使用Java EE Microservices&#xff1f; 使用Java EE API部署微服务只需要几个快速步骤。 许多人认为Java EE对于与微服务一起使用而言过于繁重&#xff0c;但事实并非如此……尤其是如果您仅利用服务所需的Java EE规范。 在这篇简短的文章中&am…

php导出页面居中设置,PHPExcel导出插入图片和居中问题

首先到网上先下载PHPExcel下载后解压得到这两个文件下载后引用该文件最后编写相关代码&#xff1a;首先是图片插入导出$objDrawing new PHPExcel_Worksheet_Drawing();$objDrawing->setName(‘Photo‘);$objDrawing->setDescription(‘Photo‘);$objDrawing->setPath…

两台电脑通过usb共享网络_怎样让电脑通过手机共享上网?

手头有部七年前买的安卓智能手机已经不用了&#xff0c;卖掉不值钱&#xff0c;放在家里也是浪费。能否让它继续发挥余热呢&#xff1f;最近找到了一个好办法&#xff0c;就是可以让个人电脑通过它来上网&#xff08;如下图所示&#xff09;&#xff1a;1. 用数据线将电脑与手机…

linux redis客户端_你见过能把Redis的主从复制讲这么明白的吗?

概念1.Conception(概念)Redis的复制也就是我们所说的主从复制&#xff0c;主机数据更新后根据配置和策略&#xff0c;自动同步到备机的master/slaver机制&#xff0c;Master以写为主&#xff0c;Slave以读为主。2.Function(功能)读写分离(秉持与RDBMS 相同的设计理念)容灾恢复R…

discuz3.1用哪个版本php版本好,Discuz应用中心安装模板提示版本号不匹配适用于X3.3 X3.2 X3.1的解决方法...

有时候我们从应用中心安装模板&#xff0c;在应用中心里模板作者设定允许我们的程序版本&#xff0c;但是我们安装时却提示版本号不匹配&#xff0c;那这是为什么呢&#xff1f;经过我们分析发现是因为X3和X3.1&#xff0c;X3.2的模板是完全兼容的&#xff0c;很多模板是在X3的…

arch linux arm下载_arm开发板运行hello word的详细过程

arm开发板运行helloword1.uboot的编译​ 这里已经安装好了交叉编译工具链&#xff0c;如果自己的电脑下没有&#xff0c;请自行百度安装。将下载好uboot到linux下&#xff0c;进行解压-->打补丁-->编译-->烧写&#xff0c;执行以下命令完成上述四个步骤&#xff08;不…

小程序 input自动换行_直播 | 最实用的微信小程序自动化测试技术独家揭秘

随着微信小程序的功能和生态日益完善&#xff0c;很多企业级小程序项目的页面越来越多&#xff0c;业务逻辑也越来越复杂。如何做好微信小程序的自动化测试成为测试同学面临的一大难题。如何合理构建多端架构和自动化测试体系&#xff1f;如何深入理解微信小程序特性和技术原理…

sit matlab,LabView SIT工具包的使用和安装说明

之前一直在用Simulink做仿真模型&#xff0c;现在要做测试需要用NI的设备和LabView软件&#xff0c;通过一段时间的学习&#xff0c;在SIT的使用上有了点小认识拿来跟大家分享一下。需要注意的是&#xff0c;必须是先安装MatLab Simulink 然后安装SIT工具包&#xff0c;如果先安…

opencv 把3通道图像转成单通道_小强学Python+OpenCV之-1.4.3图像(矩阵)加减运算

引入问题引入&#xff0c;考虑以下几个问题&#xff1a;Q1. 一个3通道像素p的BGR分量&#xff08;8bit表示&#xff09;值均相同&#xff0c;那么这个像素是什么颜色的&#xff1f;Q2. 该像素p加上自己&#xff0c;即&#xff0c;像素p的各个通道值翻倍&#xff0c;那么这个像素…

mvc 404错误 php,java - springmvc 请求无法到达controller,出现404错误

springmvc 请求无法到达controller&#xff0c;出现404错误web.xmltestmvcindex.htmlindex.htmindex.jspdefault.htmldefault.htmdefault.jspspringmvcorg.springframework.web.servlet.DispatcherServletcontextConfigLocationclasspath:springmvc-servlet.xml1springmvc/org.…

diff算法_传统Diff算法为什么时间复杂度要O(n ^3)

原文链接&#xff1a;https://juejin.im/post/6892671384976097287很多文章提到的都是新旧DOM树需要两两对比&#xff0c;但是没有说清楚为什么。思考大家想一下&#xff0c;如果让你来设计将一棵树转换为另一棵树&#xff0c;你会怎么设计&#xff1f;可能是直接暴力的根据ind…

CentOS 7 Linux 的初始化系统(系统服务管理和控制程序/Init System) -- systemd 详解

文章目录一、systemd 的由来&#xff08;一&#xff09;常用的 init 系统&#xff08;二&#xff09;init 程序的缺点&#xff08;三&#xff09;systemd 简介&#xff08;四&#xff09;systemd 架构图二、服务管理三、unit 配置文件&#xff08;一&#xff09;概述&#xff0…

python 指针指向的内容,python-文件的读取及指针位置

文件的读取及指针位置打开文件的三步&#xff1a;打开->操作->关闭文件的读取&#xff1a;f open(/tmp/passwd)打开f.close()操作完&#xff0c;关闭文件判断文件对象拥有的权限print(f.readable())是否拥有可读权限True or Falshprint(f.writable())是否拥有可写权限文…

matplotlib 柱状图_Matplotlib数据可视化:柱状图与直方图

↑↑点击上方蓝字&#xff0c;回复资料&#xff0c;嘿嘿&#xff0c;10个G的惊喜柱状图和直方图是两种非常类似的统计图&#xff0c;区别在于&#xff1a;直方图展示数据的分布&#xff0c;柱状图比较数据的大小。直方图X轴为定量数据&#xff0c;柱状图X轴为分类数据。因此&am…

groovy.run 脚本_Picocli 2.0:类固醇上的Groovy脚本

groovy.run 脚本Picocli 2.0增加了对其他JVM语言&#xff08;尤其是Groovy&#xff09;的支持。 当Groovy语言具有CliBuilder类的内置CLI支持时&#xff0c;为什么还要使用picocli&#xff1f; 您可能喜欢picocli的使用帮助&#xff0c;默认情况下会显示ANSI 颜色和样式 。 您…

Linux 系统服务管理和控制程序(初始化系统/Init System) -- systemd 介绍

文章目录systemd 简介systemd 启动过程概述Systemd的争议systemd 简介 开发systemd的主要目的就是减少系统引导时间和计算开销。systemd&#xff08;系统管理守护进程&#xff09;&#xff0c;最开始以GNU GPL协议授权开发&#xff0c;现在已转为使用GNU LGPL协议&#xff0c;…

mongodb msi安装包_跟我快速学数据存储:MongoDB非关系型数据库

想要学习更多编程&#xff0c;就点上方蓝字关注我们MongoDB概述01与Redis半持久化&#xff0c;存储于内存和硬盘不同&#xff0c;MongoDB是直接持久化&#xff0c;存储于硬盘的缓存系统。MongoDB非常流行&#xff0c;其中阿里云提供了云数据库MongoDB版。https://blog.csdn.net…

php页面 info,通过PATH_INFO方法实现页面伪静态_php

/*函数url_parse用于解析url&#xff0c;使用时需要在前面定义define(PATH_INFO,true);需要解析时调用该函数&#xff0c;取值方法用回$_GET[xxx]即可*/function url_parse(){if(!(isset($_SERVER[PATH_INFO])&&defined(PATH_INFO))){return;}$url substr($_SERVER[PA…