所以基本上我想做的是以下几点:
- 从数据库中加载一批数据
- 将该数据(查询结果)映射
Object[]
到以可读格式表示数据的类 - 写入文件
- 重复直到查询没有更多结果
我列出了我熟悉的似乎符合需求的结构,以及为什么它们不符合我的需求。
- 迭代器 → 不调用就没有映射和过滤的选项
next()
- 我需要在子类中定义映射函数,但实际上没有数据(类似于流),这样我就可以将“流”方式传递给调用类,并且只有 call
next
,然后调用所有映射函数因此
- 我需要在子类中定义映射函数,但实际上没有数据(类似于流),这样我就可以将“流”方式传递给调用类,并且只有 call
- 流 → 在映射和过滤可能之前,所有数据都需要可用
- 可观察的→一旦数据可用就发送数据。我需要同步处理它
为了更多地了解我正在尝试做的事情,我做了一个小例子:
// Disclaimer: "Something" is the structure I am not sure of now.
// Could be an Iterator or something else that fits (Thats the question)
public class Orchestrator {
@Inject
private DataGetter dataGetter;
public void doWork() {
FileWriter writer = new FileWriter("filename");
// Write the formatted data to the file
dataGetter.getData()
.forEach(data -> writer.writeToFile(data));
}
}
public class FileWriter {
public void writeToFile(List<Thing> data) {
// Write to file
}
}
public class DataGetter {
@Inject
private ThingDao thingDao;
public Something<List<Thing>> getData() {
// Map data to the correct format and return that
return thingDao.getThings()
.map(partialResult -> /* map to object */);
}
}
public class ThingDao {
public Something<List<Object[]>> getThings() {
Query q = ...;
// Dont know what to return
}
}
到目前为止我得到了什么:
我试图从 Iterator 的基础出发,因为它是唯一真正满足我的内存需求的。然后我添加了一些方法来映射和循环数据。虽然它并不是一个真正强大的设计,而且它会比我想象的更难,所以我想知道是否已经有任何东西可以满足我的需要。
public class QIterator<E> implements Iterator<List<E>> {
public static String QUERY_OFFSET = "queryOffset";
public static String QUERY_LIMIT = "queryLimit";
private Query query;
private long lastResultIndex = 0;
private long batchSize;
private Function<List<Object>, List<E>> mapper;
public QIterator(Query query, long batchSize) {
this.query = query;
this.batchSize = batchSize;
}
public QIterator(Query query, long batchSize, Function<List<Object>, List<E>> mapper) {
this(query, batchSize);
this.mapper = mapper;
}
@Override
public boolean hasNext() {
return lastResultIndex % batchSize == 0;
}
@Override
public List<E> next() {
query.setParameter(QueryIterator.QUERY_OFFSET, lastResultIndex);
query.setParameter(QueryIterator.QUERY_LIMIT, batchSize);
List<Object> result = (List<Object>) query.getResultList(); // unchecked
lastResultIndex += result.size();
List<E> mappedResult;
if (mapper != null) {
mappedResult = mapper.apply(result);
} else {
mappedResult = (List<E>) result; // unchecked
}
return mappedResult;
}
public <R> QIterator<R> map(Function<List<E>, List<R>> appendingMapper) {
return new QIterator<>(query, batchSize, (data) -> {
if (this.mapper != null) {
return appendingMapper.apply(this.mapper.apply(data));
} else {
return appendingMapper.apply((List<E>) data);
}
});
}
public void forEach(BiConsumer<List<E>, Integer> consumer) {
for (int i = 0; this.hasNext(); i++) {
consumer.accept(this.next(), i);
}
}
}
到目前为止,这是可行的,但是有一些unchecked
我不太喜欢的任务,而且我希望能够将一个 QIterator “附加”到另一个 QIterator 本身并不难,但它也应该采用后面的地图附加。