Java Generics:将通用函数对象链接在一起

我一直在努力解决以下问题。 我有一系列函数对象,每个函数对象都有自己的输入和输出类型,通过java中的generics类型参数定义。 我想在链中安排这些,以便将原始数据输入到第一个函数,转换为输出类型,这是下一个对象的输入类型,依此类推。 当然这对于硬编码来说是微不足道的,但是我想让代码可以插入到新的函数对象中。 如果我只是省略类型参数(只有最终输出类型),这就是事情的样子:

public T process() { Iterator it = source.provideData(); for(Pipe pipe : pipeline) { it = pipe.processIterator(it); } return sink.next(it); } 

这里,数据上的迭代器在函数对象之间传递,上下文应该是Context。 有没有办法保持以下类型的管道可插拔,仍然保持类型安全?

编辑:为清楚起见,我有一系列function对象,管道。 每个都将特定类型作为输入,并输出另一种类型。 (实际上是这些类型的迭代器)这些将被链接在一起,例如, Pipe -> Pipe -> Pipe -> ... ,以便输出一个pipe是下一个管道的输入类型。 这里还有一个源,它输出一个类型为A的迭代器,以及一个接受类型的接收器(过去管道的输出)。 这会让事情更清楚吗? 问题是,因为输入和输出类型的兼容性存在严重依赖性,有没有办法确保这一点?

我开始认为将函数对象插入管道可能是确保类型安全的最佳时间,但我不知道如何做到这一点。

编辑2:我有一个函数对象的加法器方法,目前如下所示:

 public void addPipe(Pipe pipe) { pipeline.add(pipe); } 

我想检查第一个类型参数是否与当前管道的“结束”相同,如果不是则抛出exception? 我不认为有一个很好的方法来获得编译时安全性。 然后可以将当前管道的“结束”设置为输入管道的第二个类型参数。 我想不出如何用generics来做这件事,并且传递类信息似乎很可怕。

这是一种方法。 run方法不是类型安全的,但是假设附加管道的唯一方法是以类型安全的方式执行,整个链是类型安全的。

 public class Chain { private List> pipes; private Chain() { } public static  Chain start(Pipe pipe) { Chain chain = new Chain(); chain.pipes = Collections.>singletonList(pipe);; return chain; } public  Chain append(Pipe pipe) { Chain chain = new Chain(); chain.pipes = new ArrayList>(pipes); chain.pipes.add(pipe); return chain; } @SuppressWarnings({ "rawtypes", "unchecked" }) public T run(S s) { Object source = s; Object target = null; for (Pipe p : pipes) { target = p.transform(source); source = target; } return (T) target; } public static void main(String[] args) { Pipe pipe1 = new Pipe() { @Override public Integer transform(String s) { return Integer.valueOf(s); } }; Pipe pipe2 = new Pipe() { @Override public Long transform(Integer s) { return s.longValue(); } }; Pipe pipe3 = new Pipe() { @Override public BigInteger transform(Long s) { return new BigInteger(s.toString()); } }; Chain chain = Chain.start(pipe1).append(pipe2).append(pipe3); BigInteger result = chain.run("12"); System.out.println(result); } } 

这是另一种方法:这种方式允许转换步骤以产生列表。 例如,转换可以将字符串拆分为多个子字符串。 此外,如果转换任何值产生exception,它允许常见的exception处理代码。 它还允许使用空List作为返回值,而不是必须进行测试的模糊空值以避免NullPointerException。 这个问题的主要问题是它在进入下一步之前完成了每个转换步骤,这可能不是内存有效的。

 public class Chain { private final Chain head; private final Transformer tail; public static  Chain makeHead(@Nonnull Transformer tail) { return new Chain<>(null, tail); } public static  Chain append(@Nonnull Chain head, @Nonnull Transformer tail) { return new Chain<>(head, tail); } private Chain(@Nullable Chain head, @Nonnull Transformer tail) { this.head = head; this.tail = tail; } public List run(List input) { List allResults = new ArrayList<>(); List headResult; if (head == null) { headResult = (List) input; } else { headResult = head.run(input); } for (MEDIAL in : headResult) { // try/catch here allResults.addAll(tail.transform(in)); } return allResults; } public static void main(String[] args) { Transformer pipe1 = new Transformer() { @Override public List transform(String s) { return Collections.singletonList(Integer.valueOf(s) * 3); } }; Transformer pipe2 = new Transformer() { @Override public List transform(Integer s) { return Collections.singletonList(s.longValue() * 5); } }; Transformer pipe3 = new Transformer() { @Override public List transform(Long s) { return Collections.singletonList(new BigInteger(String.valueOf(s * 7))); } }; Chain chain1 = Chain.makeHead(pipe1); Chain chain2 = Chain.append(chain1, pipe2); Chain chain3 = Chain.append(chain2, pipe3); List result = chain3.run(Collections.singletonList("1")); System.out.println(result); } }