寻求正确的模式将相同的规则应用于不同的数据集

时间:2012-07-26 20:44:02

标签: java algorithm design-patterns

假设您的内存中有List<Elements>List<Files>,其中每个都是List<Elements>的序列化表示

目标是针对每个元素执行相同的算法。

让我们说工作是计算元素

int i = 0;
for (Element e : list) {
       ++i;
}

for (File f : directory()) {
    for (Element e : listWeSomehowGetFromTheFile) {
           ++i;
    }
}

这可以以某种方式进一步抽象吗?基本上,算法是相同的(++i)。有没有办法清理它?

我当然可以拥有它自己的类Counter(List<Element>),它有count ()方法在列表中运行算法。这样我们就可以:

 i+=Counter.count(list);
 for (File f : directory()) {
   i+=Counter.count(listWeSomehowGetFromTheFile);
 }

但即使这似乎可以改进。

出于本示例的目的,我们假设所有操作(其中一组)将在内存中的列表上执行,而一个列表来自相同目录中的相同文件。唯一可以改变的是算法。

哪种模式最适合处理这样的事情?

2 个答案:

答案 0 :(得分:1)

当您想对集合中的每个项目执行某些操作时,Visitor Pattern非常受欢迎。

访问者模式也很好,因为它允许您扩展您可以执行的计算,而无需重写访问者操作的类。

如果您不需要完全遵循正式模式,

1)使用方法Operation定义类似calculate的界面,该方法采用元素并进行操作。
2)您的计算是Operation的实施 3)遍历元素,将元素传递给操作实现。

如果计算结果是累积的(取决于先前对其他元素的计算调用),则可以修改calculate以获取包含计算状态的对象,然后在calculate为针对元素触发,您更新状态。您继续将相同的状态对象传递给每个计算调用。

作为大纲(不会编译):

public Interface Operation {
   // don't necessarily need state
   public void calculate (Element e, State state);
}

CountOp extends Operation {
   count = 0;

   public void calculate(Element e, State state){
      // not using element or state because this is so simple....
      count++;
   }
}

Operation op = new CountOp();
State state = new SomeStateImpl();
for (File f : directory()) {
    for (Element e : listWeSomehowGetFromTheFile) {
          op.calculate(e, state);
    }
}

答案 1 :(得分:0)

我可能会误解,但我接近这个问题的方法是根据(懒惰)序列编写函数 - 很容易将列表和数据从文件转换为惰性值序列。

在更实际的术语中,java中的延迟流通常被实现为迭代(或迭代器,如果你不需要重新启动),并且guava库有许多utilities来处理这些。

这假设元素属于同一类型。访问者模式更适合于当您处理的数据结构具有不同类型时(访问者是您基于类型的调度的位置;对于单个类型而言,这不是必需的,因此单个类型的访问者模式等同于生成流数据 - 在这种情况下,使用现有的迭代器更简单。)