设计模式应用于文本规范化链

3
我有一个程序,定期接收包含多行内容的文件,我逐行处理。为了处理这些行,我开发了一些文本规范化器来转换它们。例如,一种规范化可能是去除停用词、语法纠正、删除网址等。
针对给定文件使用的规范化器必须动态决定,以便我可以更改它们的数量并改变其顺序。对于某些文件,我只需要去除停用词,但其他文件需要更多的规范化器,并且在某些情况下我必须两次应用其中一个规范化器。
我最初组织代码的想法是应用“责任链”模式。在这种情况下,我将拥有如下内容:
如图所示,在顺序中使用了三个规范化器,然后再次使用第一个规范化器。这仅是一个示例。在其他情况下,我可能会有7个不重复的规范化器,而在另一种情况下,第二个规范化器将在第三个规范化器之前执行。因此,主要思想是拥有多个规范化器,并定义一个链路,其中我可以重复。
我对这种方法的问题在于,链中的所有成员始终被执行(无拒绝条件),而且我必须处理成千上万行数据,所以我不想花费大量时间迭代链。
因此,我的问题是,如何实现我所需的功能,使我有机会添加新的规范化器而无需重写代码,并保持高速的链迭代速度?
如果您需要更多信息,请告诉我,我将编辑问题。

你根据什么条件决定需要哪个规范化程序? - Bart
接收到的文件包含了那些信息。 - David Moreno García
1
我不确定为什么您需要这个设计模式。如果每行都需要由给定的规范化程序进行处理,那么它非常直截了当。您只需拥有一个规范化程序列表并逐行迭代即可。 - Bart
4个回答

1
当您为每行执行所有规范化程序时,设计模式是命令列表,因为没有对每个规范化程序的责任进行检查。
据我所知,每个文件的规范化程序列表是恒定的,因此创建它不是问题。而且您说您为每行迭代所有规范化程序,因此唯一可以调整性能的是迭代本身。
我会使用这样的设计: 1)所有规范化程序实现一个共同的接口
interface Normalizer {
  String normalize(String line);
}

你很可能已经有类似的东西了。
2)打开文件(或开始处理它)时,您确定需要哪些规范化器。除非您的文件很短并且有很多文件,否则您如何做并不重要。您可以拥有一个工厂,返回某些标准的规范化器列表。它可以使用一份类名的文本列表或创建硬编码的命令列表。还要考虑Joop Eggen在这里的回答。
class Factory {
  List<Normalizer> buildNormalizers(DeterminingCriteria criteria) { ... } 
}

如果您需要在不重新部署的情况下更改列表,则带有类名列表的文本文件非常方便。如果您在此时还需要添加新的规范化程序,则无论如何都需要更改代码,因此构建规范化程序列表的类也可以。由于这里的规范化程序需要是无状态的,因此您可以在列表中重用双重规范化程序。实际上,除非您的应用程序一遍又一遍地启动每个文件,否则您可以为所有文件重用所有规范化程序。由于您的命令是无状态的,因此如果需要,它们也可以同时在不同的文件上工作。也许使用这样的设计:
  class Factory {
    private Map<Criteria, Normalizer> cachedNormalizers;
    public Factory() {
      // create all normalizers from a master map 
      // or hard coded here and add to map.
    }
    List<Normalizer> buildNormalizers(DeterminingCriteria criteria) { 
      // create an empty list and get normalizers from 
      // cached map depending on criterias you need.   
    } 
  }

3)然后,在主代码中,您只需为每一行迭代这些内容。迭代列表应该非常快,就像这样(伪代码):

List<Normalizer> normalizers = factory.buildNormalizers(currentFileCriteria);
for (String line in lines) {
  String currentLine = line;
  for (Normalizer n in normalizers) {
    currentLine = n.normalize(currentLine);
  }
  doSomethingWithFinished(currentLine);
}

1
"My problem with this approach is that all the members of the chain are executed always (no reject condition) and I have thousand and thousand of lines to process so I don't want to spend a lot of time iterating over the chain."
"我的问题是这种方法总是执行链中的所有成员(没有拒绝条件),而我需要处理成千上万行,所以我不想花费大量时间迭代整个链。"
David,
这有点矛盾。你说你想要按顺序执行所有的规范化程序,例如1、2、3、1,对文件中的每一行都执行一次。但是你又说你的问题是你执行了所有的规范化程序,这可能会减慢速度。这个规范化程序的顺序是否取决于你正在处理的当前行?如果不依赖于当前行,而且你需要在所有行上运行1、2、3、1,则只需这样做即可。我真的看不出你如何避免调用某些规范化程序,同时仍然在每行上调用它们全部。

谢谢你的回答。我并不是试图避免一些调用。我只是在寻找一种快速实现,以便在迭代链表时不浪费太多时间。 - David Moreno García
David,快速实现更多地与算法有关,而不是设计模式。我认为我在你以前的问题中也提到了这一点。 - peter.petrov
当然可以,这也是我的问题的一部分。我可以使用列表,类似于责任链模式实现中使用的方法等。我想知道您认为哪种方法可能是最快的。 - David Moreno García
@MorenoGarcia 你是遇到了性能问题还是试图过早地进行优化?我建议你只需以最简单的方式实现它,如果出现性能瓶颈,再进行调查并进行改进。 - Bart

1
我不知道以下内容是否符合您的架构理念。
从XML中的声明性控制模型开始:
- 标准化器。 - 每个标准化器可以提供的控制消息。 - 标准化器的默认序列。 - 对于每个控制消息,需要执行的操作 - “之后添加标准化器3,删除之前的标准化器1”。
这样可以推断出更改的综合效果。将控制消息(不再使用标签)与实际操作(删除标准化器标签)分离可能是适当的。
可以使用POJO和注释使用JAXB读取XML。非常容易。
控制粘合剂可以记录所有内容,因此可以确定没有发生次优的事情。

1
我会查看Lucene的分析器设计,它基本上是复合对象(Analyzer)的抽象工厂,并完成与您描述的类似的任务。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接