代理模式介绍

  • 代表:被选中或当选为他人投票或代表他人的人– Merriam-Webster 。
  • 委托模式:在软件工程中,委托模式是面向对象编程中的一种设计模式,其中,一个对象而不是执行其声明的任务之一,而是将该任务委托给一个关联的辅助对象Wikipedia 。
  • 让事情尽可能简单,但不要简单- 爱因斯坦 Albert Einstein)释义

Spring Batch是Enterprise Java工具箱中的重要工具。 它提供了开箱即用的强大功能,尤其是从不同来源读取和写入数据时。 我们在此博客中提供了几篇介绍Spring Batch的文章。 如果您不熟悉Spring Batch和Reader,Processor,Writer Tasklet,请花点时间回顾一下。

我上面使用的措辞对我来说很重要。 我尝试做的一件事就是保持我提供的代码尽可能可维护。 我希望它能正常工作,但是我今天签入的代码将在以后某个日期由某些人维护。 保持代码尽可能简单是确保代码易于维护的一种方法。

那么,当您必须处理复杂的数据源时会发生什么呢?

我们发现,经常要处理的输入文件并不像每行一个记录那么简单。 通常,文件中有多行仅描述一条记录。

例如:

HKaren Traviss
LAB00KW3VG2G
LI0345478274
LI0345511131
F00000003
HJim Butcher
LI0451457811
F00000001
HDave Duncan
LI0380791277
LI0345352912
F00000002
HRik Scarborough
LI9999999999
F00000001

在这里,我们有一个文件,其中包含十五行中的四个记录。 每条记录均以页眉行开头,包含一个或多个正文行,并以页脚结尾。 标头包含线型(标头为H)和名称。 该行还包含线型(L),查找类型(在此示例中为ISBN或Amazon代码)以及查找书本的键。 页脚再次包含线型和此块中的记录数。

使用标准的读取器,将读取每一行,然后传递给处理器,然后处理器必须确定处理的是哪种类型的行。 然后,处理程序在处理每条正文行时,处理程序将必须保留来自每个标头的信息,直到处理了页脚。 然后,编写者将必须知道处理器发送的每一行,以及是否应将其写入。 这很复杂,部分是因为多个对象必须知道如何读取文件,而不是处理器仅关心单个对象,而编写器仅关心编写给出的内容。

相反,让我们将Delegate模式引入Reader并让其处理创建整个记录的过程。 由于我们具有来自多行的信息以及用于创建每个记录的页眉和页脚,因此我们必须将记录列表传递给处理程序。 你们当中的观察者会注意到,每个记录都包含一个ISBN或Amazon图书符号,并且可以用来查找作者(也包含在标题中)。 在现实生活中,这种冗余可能也不会发生。

让我们将输出包装在另一个对象中,以使其更易于使用。

public class OrderReaderStep implements ItemReader<OrderList> {private static final Logger logger = LoggerFactory.getLogger(OrderReaderStep.class);private FlatFileItemReader
<FieldSet> delegate;private static final String FOOTER = "F*";private static final String BODY = "L*";private static final String HEADER = "H*";@BeforeSteppublic void beforeStep(StepExecution stepExecution) {delegate = new FlatFileItemReader<>();delegate.setResource(new ClassPathResource("orders.txt"));final DefaultLineMapper
<FieldSet> defaultLineMapper = new DefaultLineMapper<>();final PatternMatchingCompositeLineTokenizer orderFileTokenizer = new PatternMatchingCompositeLineTokenizer();final Map<String, LineTokenizer> tokenizers = new HashMap<>();tokenizers.put(HEADER, buildHeaderTokenizer());tokenizers.put(BODY, buildBodyTokenizer());tokenizers.put(FOOTER, buildFooterTokenizer());orderFileTokenizer.setTokenizers(tokenizers);defaultLineMapper.setLineTokenizer(orderFileTokenizer);defaultLineMapper.setFieldSetMapper(new PassThroughFieldSetMapper());delegate.setLineMapper(defaultLineMapper);delegate.open(stepExecution.getExecutionContext());}@AfterSteppublic void afterStep(StepExecution stepExecution) {delegate.close();}@Overridepublic OrderList read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {logger.info("start read");OrderList record = null;FieldSet line;List<Order> bodyList = new ArrayList<>();while ((line = delegate.read()) != null) {String prefix = line.readString("lineType");if (prefix.equals("H")) {record = new OrderList();record.setName(line.readString("name"));} else if (prefix.equals("L")) {Order order = new Order();order.setLookup(line.readString("lookupKey"));order.setLookupType(line.readString("keyType"));bodyList.add(order);} else if (prefix.equals("F")) {if (record != null) {if (line.readLong("count") != bodyList.size()) {throw new ValidationException("Size does not match file count");}record.setOrders(bodyList);}break;}}logger.info("end read");return record;}private LineTokenizer buildBodyTokenizer() {FixedLengthTokenizer tokenizer = new FixedLengthTokenizer();tokenizer.setColumns(new Range[]{ //new Range(1, 1), // lineTypenew Range(2, 2), // keyTypenew Range(3, 12) // lookup key});tokenizer.setNames(new String[]{ //"lineType","keyType","lookupKey"}); //tokenizer.setStrict(false);return tokenizer;}private LineTokenizer buildFooterTokenizer() {FixedLengthTokenizer tokenizer = new FixedLengthTokenizer();tokenizer.setColumns(new Range[]{ //new Range(1, 1), // lineTypenew Range(2, 9) // count});tokenizer.setNames(new String[]{ //"lineType","count"}); //tokenizer.setStrict(false);return tokenizer;}private LineTokenizer buildHeaderTokenizer() {FixedLengthTokenizer tokenizer = new FixedLengthTokenizer();tokenizer.setColumns(new Range[]{ //new Range(1, 1), // lineTypenew Range(2, 20), // name});tokenizer.setNames(new String[]{ //"lineType","name"}); //tokenizer.setStrict(false);return tokenizer;}}

此Reader实现ItemReader接口。 这为我们提供了一个由作业调用的read方法,直到它返回null或发生错误时引发异常。 在我们的Reader中,我们声明另一个Reader,这是一个FlatFileItemReader。 这是我们的代表,即为我们执行功能所选择的对象。 我们的read方法将以委托的读取为循环,直到读取Footer。 然后它将整个记录捆绑到其包装器中,并将其传递给处理器。

必须先打开委托阅读器,然后才完成使用。 我必须在此处将它初始化并在此处进行设置,因此在BeforeStep中在此处打开它。 我也可以将包含的阅读器实现为ItemStreamReader,并使用Interface给我们的open,close以及update方法。

将简化的对象返回给Processor可以使我们大大简化Processor:

@Override
public List<BookList> process(OrderList orderList) throws Exception {logger.info("process");List<BookList> books = new ArrayList<>();for (Order order : orderList.getOrders()) {BookList bl = doProcessing(orderList.getName(), order);books.add(bl);}return books;
}

doProcessing方法可以包含此Job的业务逻辑,并且需要创建一个有效的BookList对象。 由于我们正在处理多个记录,因此该过程将创建多个可返回的BookList,并将其传递给Writer。 我将留给您填写该对象的其余部分,但这只是一个标准的ItemProcessor。 处理器不必在调用之间保留记录信息,因此程序员可以专注于业务逻辑。

我们的编写器实现ItemStreamWriter。 这为我们提供了比ItemWriter更多的方法,但是,如果您喜欢使用ItemWriter(类似于我们阅读器的方法),请确保在BeforeStep中打开Delegate,在AfterStep中将其关闭。

在Writer中使用委托使我们能够遍历Writer从Reader和Process收到的List。

public class ListWriter implements ItemStreamWriter<List<BookList>> {private static final Logger logger = LoggerFactory.getLogger(ListWriter.class);private FlatFileItemWriter<BookList> delegate;@BeforeSteppublic void beforeStep(StepExecution stepExecution) {delegate = new FlatFileItemWriter<>();delegate.setResource(new FileSystemResource("booklist.csv"));delegate.setShouldDeleteIfEmpty(true);delegate.setAppendAllowed(true);DelimitedLineAggregator<BookList> dla = new DelimitedLineAggregator<>();dla.setDelimiter(",");BeanWrapperFieldExtractor<BookList> fieldExtractor = new BeanWrapperFieldExtractor<>();fieldExtractor.setNames(new String[]{"bookName", "author"});dla.setFieldExtractor(fieldExtractor);delegate.setLineAggregator(dla);}@Overridepublic void close() throws ItemStreamException {delegate.close();}@Overridepublic void open(ExecutionContext ec) throws ItemStreamException {delegate.open(ec);}@Overridepublic void update(ExecutionContext ec) throws ItemStreamException {delegate.update(ec);}@Overridepublic void write(List<? extends List<BookList>> list) throws Exception {logger.info("write");for (List<BookList> bookList : list) {delegate.write(bookList);}}}

这为我们提供了以下输出:

Going Grey,Karen Traviss
Hard Contact,Karen Traviss
501st,Karen Traviss
Storm Front,Jim Butcher
Lord of the Fire Lands,Dave Duncan
The Reluctant Swordsman,Dave Duncan
Wolfbrander Series Unpublished,Rik Scarborough

那么,如果稍微复杂一些并且输入文件不包含页脚,会发生什么呢?

逻辑记录仍然从标题行开始,但在下一个标题之前的行结束。 在我们之前的示例中,系统必须先读取下一行,然后才能知道已完成,然后具有一些复杂的逻辑来保留该信息以进行下一个遍历。

HKaren Traviss
LAB00KW3VG2G
LI0345478274
LI0345511131
HJim Butcher
LI0451457811
HDave Duncan
LI0380791277
LI0345352912
HRik Scarborough
LI9999999999

要求我们当前的作者在下一次电话会议之前先阅读并保留该记录是不必要的复杂操作,这会导致维护麻烦。 但是,我们可以使用PeekableItemReader简化此过程:

class OrderReaderStep2 implements ItemStreamReader<OrderList> {private static final String BODY = "L*";private static final String HEADER = "H*";private static final Logger logger = LoggerFactory.getLogger(OrderReaderStep2.class);private SingleItemPeekableItemReader
<FieldSet> delegate;@BeforeSteppublic void beforeStep(StepExecution stepExecution) {FlatFileItemReader fileReader = new FlatFileItemReader<>();fileReader.setResource(new ClassPathResource("orders2.txt"));final DefaultLineMapper
<FieldSet> defaultLineMapper = new DefaultLineMapper<>();final PatternMatchingCompositeLineTokenizer orderFileTokenizer = new PatternMatchingCompositeLineTokenizer();final Map<String, LineTokenizer> tokenizers = new HashMap<>();tokenizers.put(HEADER, buildHeaderTokenizer());tokenizers.put(BODY, buildBodyTokenizer());orderFileTokenizer.setTokenizers(tokenizers);defaultLineMapper.setLineTokenizer(orderFileTokenizer);defaultLineMapper.setFieldSetMapper(new PassThroughFieldSetMapper());fileReader.setLineMapper(defaultLineMapper);delegate = new SingleItemPeekableItemReader<>();delegate.setDelegate(fileReader);}@Overridepublic void close() throws ItemStreamException {delegate.close();}@Overridepublic void open(ExecutionContext ec) throws ItemStreamException {delegate.open(ec);}@Overridepublic OrderList read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {logger.info("start read");OrderList record = null;FieldSet line;List<Order> bodyList = new ArrayList<>();while ((line = delegate.read()) != null) {String prefix = line.readString("lineType");if (prefix.equals("H")) {record = new OrderList();record.setName(line.readString("name"));} else if (prefix.equals("L")) {Order order = new Order();order.setLookup(line.readString("lookupKey"));order.setLookupType(line.readString("keyType"));bodyList.add(order);}FieldSet nextLine = delegate.peek();if (nextLine == null || nextLine.readString("lineType").equals("H")) {record.setOrders(bodyList);break;}}logger.info("end read");return record;}@Overridepublic void update(ExecutionContext ec) throws ItemStreamException {delegate.update(ec);}private LineTokenizer buildBodyTokenizer() {FixedLengthTokenizer tokenizer = new FixedLengthTokenizer();tokenizer.setColumns(new Range[]{ //new Range(1, 1), // lineTypenew Range(2, 2), // keyTypenew Range(3, 12) // lookup key});tokenizer.setNames(new String[]{ //"lineType","keyType","lookupKey"}); //tokenizer.setStrict(false);return tokenizer;}private LineTokenizer buildHeaderTokenizer() {FixedLengthTokenizer tokenizer = new FixedLengthTokenizer();tokenizer.setColumns(new Range[]{ //new Range(1, 1), // lineTypenew Range(2, 20), // name});tokenizer.setNames(new String[]{ //"lineType","name"}); //tokenizer.setStrict(false);return tokenizer;}}

这次,我确实将包含的Reader实现为ItemStreamReader,以向您展示它们之间的区别。 可以像上一个一样将其实现为ItemReader。

PeekableItemReader允许我们向前查看下一条记录,以查看是否到达记录的末尾或文件的末尾。 然后可以使用相同的处理器和写入器来产生与以前相同的输出。

最后的想法

乍一看,委托模式似乎不像使用单个读取器或写入器那么简单。 这两个对象都有更多的配置。 但是我最喜欢的释义是说要尽可能简单,而且再简单不过。 稍微复杂一点的Reader和Writer将使您的Processor更加简单,并有助于后续维护。

代码很好,我的朋友。

翻译自: https://www.javacodegeeks.com/2016/03/introducing-delegate-pattern.html

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

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

相关文章

江西理工大学 微型计算机原理,江西理工大学-微机原理考试(wenwei)作业.docx

江西理工大学-微机原理考试(wenwei)作业第一章1. 在计算机内部为什么要采用二进制数而不采用十进制数&#xff1f;  2. 设机器字长为6位&#xff0c;写出下列各数原码、补码和移码&#xff1a;  10101 11111 10000 ?-10101 -11111 -10000  3. 利用补码进行加/减法运算比…

C语言中数组做函数参数的问题

数组做函数参数&#xff0c;会退化成为一个指针变量。因此在进行数组参数传递的同时&#xff0c;需要传递一个数组长度的参数变量。 数组长度可以通过sizeof(arr)/siezof(arr[0])来得到。关于这个sizeof操作符&#xff0c;简单的理解就是求得指针指向的内存块的大小。 当数组作…

计算机图形标定学,计算机图形学(璩柏青)第10章空间形体的三维重建与图像处理.ppt...

计算机图形学(璩柏青)第10章空间形体的三维重建与图像处理相应可得到各单元方程组集&#xff0c; 即总体方程为 整个SFS问题求解是一个逐次线性化过程&#xff0c;可按如下步骤实现&#xff1a; (1) 先给定一定的初值R(p,q)&#xff1b; (2) 局部线性化反射图函数&#xff…

线程并发库和线程池的作用_并发–顺序线程和原始线程

线程并发库和线程池的作用不久前&#xff0c;我参与了一个项目&#xff0c;该项目的报告流程如下&#xff1a; 用户会要求举报 报告要求将被翻译成较小的部分 基于零件/节的类型的每个零件的报告将由报告生成器生成 组成报告的各个部分将重新组合成最终报告&#xff0c;并返…

ipad2018编写html,IT教程:ipad6是ipad2018吗

科技就如同电灯发出的光一样&#xff0c;点亮我们的世界&#xff0c;点亮我们的生活&#xff0c;这一段时间以来ipad6是ipad2018吗的消息络绎不绝是什么原因呢?接下来就让我们一起了解一下吧。大家好&#xff0c;我是智能客服时间君&#xff0c;上述问题将由我为大家进行解答。…

Web工程师修行笔记_必备单词(第三部)

历经千辛万苦&#xff0c;整理了软件开发过程中必备英文单词&#xff0c;助你走向编程巅峰 !!! 连最难的英文单词你都征服了&#xff0c;你还怕什么&#xff1f; (拒绝死记硬背&#xff0c;平时多看看&#xff0c;多用于代码中&#xff0c;&#xff09; 【不求全部都会&#xf…

流的多层次分组

1.简介 使用Java 8流&#xff0c;可以很容易地根据不同的标准对对象集合进行分组。 在这篇文章中&#xff0c;我们将看到如何从简单的单级分组到更复杂的&#xff0c;涉及多个级分组的分组。 我们将使用两个类来表示我们要分组的对象&#xff1a;人和宠物。 人类 public cla…

华为微型计算机b515,华为MateStation B515台式机曝光:五种配置

之前华为官网曾上架了台式机MateStation B515&#xff0c;这引起了很多网友的关注&#xff0c;不过实际情况是&#xff0c;它只是针对政企渠道&#xff0c;不过官方当时并没有给出新品的售价。从网友最新曝光的细节看&#xff0c;MateStation B515要比之前传闻的价格便宜不少&a…

冈仁波齐

昨日看了《冈仁波齐》&#xff0c;其实第一次听这部电影还是在网易云看到朴树的新歌《No Fear In My Heart》时知道有这样一部电影的&#xff1b; 抱着好奇心去看&#xff0c;发现这确实是一部不错的电影&#xff0c;具体好在哪里我也不是说得很清楚&#xff0c;只知道我在看电…

计算机图形相关输出设备,计算机图形输出设备.ppt

计算机图形输出设备第2章 计算机图形系统 2.1 计算机图形系统概述 2.2 基于Windows的图形程序开发方法 2.3 OpenGL介绍 2.1 计算机图形系统概述 2.1.1 计算机图形外部设备 新型显示器 计算机图形输入设备 计算机图形输出设备 2.1.2 计算机图形软件 几何造型平台 CAD/CAM 计算机…

Linux下用ls和du命令查看文件以及文件夹大小

ls的用法 ls -l |grep "^-"|wc -l或find ./company -type f | wc -l 查看某文件夹下文件的个数&#xff0c;包括子文件夹里的。 ls -lR|grep "^-"|wc -l 查看某文件夹下文件夹的个数&#xff0c;包括子文件夹里的。 ls -lR|grep "^d"|wc -l …

四川高职计算机二本线学校,全网首发!四川省本科二批次2019年对口高职投档录取线出炉...

原标题&#xff1a;全网首发&#xff01;四川省本科二批次2019年对口高职投档录取线出炉四川省2019年高校招生本科录取接近尾声&#xff0c;二本批次征集志愿于8月1日进行。与此同时&#xff0c;专科批相关录取工作也进入我们视野。四川省各高校2019年对口高职调档线我省高职院…

app engine_App Engine中的Google Services身份验证,第1部分

app engine这篇文章将说明如何构建一个简单的Google App Engine&#xff08;GAE&#xff09;Java应用程序&#xff0c;该应用程序可以针对Google进行身份验证&#xff0c;并利用Google的OAuth授权访问Google的API服务&#xff08;例如Google Docs&#xff09;。 此外&#xff0…

Angular最新教程-第六节编写响应式导航栏

这节课我们讲解如何使用bootstrap 4 编写响应式布局。 参考图我们还是参照Angular中文社区http://www.angularjs.cn/ 图中标注红色的部分&#xff0c;我自己不是很喜欢&#xff0c;所以做了一点小改动。 他这里也没有做响应式布局&#xff0c;所以样式就不抄他的&#xff0c…

使用Spring-Retry重试处理

只要软件组件相互通信&#xff0c;就有可能出现临时的自我纠正错误。 此类故障包括服务的暂时不可用&#xff0c;网络连接的暂时丢失或服务繁忙时出现的超时。 在这种情况下&#xff0c;适当的重试处理可以减少这些故障可能引起的问题。 在这篇文章中&#xff0c;我们将看到如…

计算机在智慧交通的应用论文,智能交通的毕业论文

智能交通的毕业论文智能运输系统的研究许多国家都投入了巨大的人力和物力,并成为继航空航天、军事领域之后高新技术应用最集中的领域。下面为大家分享了有关智能交通的论文&#xff0c;欢迎欣赏&#xff01;摘 要&#xff1a;八十年代以来&#xff0c;世界一些发达国家纷纷投入…

MySQL5.5安装教程

1、 官网下载mysql5.5 下载地址&#xff1a; http://dev.mysql.com/downloads/mysql/5.5.html#downloads 2、 安装mysql5.5 注意&#xff0c;安装之前&#xff0c;请关闭杀毒软件。 &#xff08;1&#xff09; 打开下载的mysql-5.5.53-winx64.msi &#xff08;2&#xff09; 点…

计算机软件硬件基础知识,计算机硬件基础_计算机软硬件基础知识都包括什么具体的内容...

计算机硬件基础怎么学过去有许多微型计算机原理的书&#xff0c;讲或的原理现在肯定还有这方面的书&#xff0c;但讲的是什么我就不知道了还有学学单片机也可以对计算机硬件原理有所了解还可看有关杂志&#xff0c;如《微型计算机》&#xff0c;刚开始可能许多文章都看不懂&…

php里的抽象类和接口

//实例化类产生对象。//class fenbi//{// //普通成员&#xff0c;属于对象// public $length "10cm";// //静态成员&#xff0c;静态变量&#xff0c;属于类。// public static $color;//// //普通方法可以调用静态成员// function hua(){// echo $this->l…

新疆计算机二级慨库,2020新疆维吾尔自治区计算机二级易考套餐:二级MS Office高级应用全程班(网课+题库+教材)...

&nbsp&nbsp[导读]:2020新疆维吾尔自治区计算机二级易考套餐&#xff1a;二级MS Office高级应用全程班(网课题库教材)&#xff0c;更多新疆等级考试易考套餐&#xff0c;请访问易考吧新疆等级考试栏目2020新疆维吾尔自治区计算机二级易考套餐&#xff1a;二级MS Office高…