源程序来自于Daniel Lowe的patent-reaction-extraction项目
问题:
在分析代码的时候发现创建具备作用域范围的List<ExperimentalSection>
时,ExperimentalSectionCreator
对象中包含的处理流程复杂且难以看懂。存在以下问题:
- 流程复杂不利于修改
- 不利于替换具体的处理逻辑
- 不利于收集运行信息
分析
对源码有兴趣可以通过文章顶部的链接直接去仓库找到dan2097.org.bitbucket.reactionextraction.ExperimentalSectionsCreator
。作者在处理传入的headingsAndParagraphs时,使用大量分支判断,方法来回跳转增加不必要的阅读难度,同时又出现很多不必要的语句重复。
经过分析,在这里其实作者将专利文档做了如下分类
- 标题
- 次要标题
- 行内标题
- 段落
其中,次要标题只影响步骤的组装,其他三类需要专门的处理步骤。
这时,作者的写法就暴露出不少问题。
首当其冲就是不利于拓展,如果我们需要增加一种分类呢?加在哪里,如何复用他的方法都是问题。
其次不能利用多线程,由于Section的组装依赖于列表顺序,否则无法按照段落情况划分Section的范围,这里只能单线程顺序执行。但是其中多次涉及分类和打标签这种无关与顺序的步骤,而这些操作都是调用第三方工具且耗时不短,顺序调用带来大量不必要的延时,完全可以将这些对数据的预处理提前,并发执行之后再利用CountDownLatch
控制结果都到达后向下执行。
解决方案
首先要抛弃作者的这种写法。对于不同的分类编写专门的处理器,然后利用责任链模式,将这些处理器串起来。每个处理器只关心自己能否处理当前DOM元素,不能处理就交给下一个处理器,能处理就直接返回结果,不再向后方传递。这样,如果我们需要增加分类,只要向责任链添加新的处理器即可,同时还可以通过调整进入责任链的顺序实现对处理流程的编排控制。如此实现算法和流程的分离,也有利于收集不同处理器的输入输出数据,便于调试分析。
其次,增加预处理机制,对于后续步骤中必须存在且无关顺序的公共步骤,提前到顺序处理之前,然后利用多线程做并行处理。
网友评论