假设您的内存中有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);
}
但即使这似乎可以改进。
出于本示例的目的,我们假设所有操作(其中一组)将在内存中的列表上执行,而一个列表来自相同目录中的相同文件。唯一可以改变的是算法。
哪种模式最适合处理这样的事情?
答案 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来处理这些。
这假设元素属于同一类型。访问者模式更适合于当您处理的数据结构具有不同类型时(访问者是您基于类型的调度的位置;对于单个类型而言,这不是必需的,因此单个类型的访问者模式等同于生成流数据 - 在这种情况下,使用现有的迭代器更简单。)