Java泛型:将泛型函数对象链接在一起 [英] Java Generics: chaining together generic function object

查看:122
本文介绍了Java泛型:将泛型函数对象链接在一起的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  public T process() {
迭代器<上下文> it = source.provideData();
for(Pipe pipe:pipeline){
it = pipe.processIterator(it);
}
return sink.next(it);
}

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

编辑:
为了清晰起见,我有一系列的函数对象,管道。每个输入一个特定类型并输出另一个类型。 (实际上是这些类型的迭代器),它们将被链接在一起,例如 Pipe - >管< B,C> - >管< C,d取代; - > ... ,这样一个管道的输出就是下一个管道的输入类型。这里还有一个源代码输出A类型的迭代器和一个接受类型(过去管道的输出)的接收器。这是否使事情更清楚?问题是,由于输入和输出类型的兼容性存在严重依赖性,有没有办法确保这一点?


我开始认为将函数对象插入管道中可能是确保类型安全性的最佳时机,但我不确定如何执行此操作。



编辑2:
i有一个函数对象的加法器方法,当前看起来像下面这样:

  public void addPipe(Pipe <?,?> pipe){
pipeline.add(pipe);
}

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

解决方案

这是一种方法。 run方法不是类型安全的,但考虑到追加管道的唯一方法是以类型安全的方式执行,整个链是类型安全的。

  public class Chain< S,T> {
私人列表< Pipe<?,?>>管道;

私有链(){
}

公共静态< K,L>链< K,L>开始(管管){
链< K,L>链=新链< K,L>();
chain.pipes = Collections。< Pipe<?,?>> singletonList(pipe);;
回报链;
}

public< V>链< S,V> append(Pipe pipe){
Chain< S,V> chain = new Chain< S,V>();
chain.pipes = new ArrayList< Pipe<?,?>>>(pipes);
chain.pipes.add(pipe);
回报链;

$ b $ @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< String,Integer> pipe1 = new Pipe< String,Integer>(){
@Override
public Integer transform(String s){
return Integer.valueOf(s);
}
};
Pipe< Integer,Long> pipe2 = new Pipe< Integer,Long>(){
@Override
public Long变换(Integer s){
return s.longValue();
}
};
Pipe< Long,BigInteger> pipe3 = new Pipe< Long,BigInteger>(){
@Override
public BigInteger transform(Long s){
return new BigInteger(s.toString());
}
};
Chain< String,BigInteger> chain = Chain.start(pipe1).append(pipe2).append(pipe3);
BigInteger结果= chain.run(12);
System.out.println(result);
}
}


I've been struggling with the following problem. I have a series of function objects, each with it's own input and output types defined via generic type arguments in java. I would like to arrange these in a chain so that raw data is input to the first function, transformed to the into the output type, which is the input type of the next object, and so on. of course this would be trivial to hard-code, but i'd like to have the code be pluggable to new function objects. if i just leave out type arguments (only the final output type), this is how things look:

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

here an iterator over the data is passed between function objects, and context should be Context. is there a way to keep the following kind of pipe pluggable and still maintain type safety?

edit: for clarity, i have a series of function objects, pipes. each takes as input a particular type and outputs another type. (actually an iterators over these types) these will be chained together, eg, Pipe<A,B> -> Pipe<B,C> -> Pipe<C,D> -> ..., so that the output of one pipe is the input type for the next pipe. There is also a source here that outputs an iterator of type A, and a sink that would accept type (the output of the past pipe). does this make things clearer? The question is, because there is critical dependence on the compatibility of input and output types, is there a way to ensure this?

I am starting to think that on insert of the function objects into the pipeline may be the best time to ensure type safety, but i'm not sure how to do this.

edit 2: i have a adder method for the function objects that currently looks like below:

public void addPipe(Pipe<?,?> pipe) {
    pipeline.add(pipe);
}

i'd like to check if the first type parameter is the same as the "end" of the current pipe, and throw an exception if not? i dont think there is a good way to get compile time safety here. the "end" of the current pipe can then be set to the second type param of the input pipe. I can't think of how to do this with generics, and passing around the class information seems pretty hideous.

解决方案

Here's a way to do it. The run method is not typesafe, but given that the only way to append a pipe is to do it in a type-safe way, the whole chain is type-safe.

public class Chain<S, T> {
    private List<Pipe<?, ?>> pipes;

    private Chain() {
    }

    public static <K, L> Chain<K, L> start(Pipe<K, L> pipe) {
        Chain<K, L> chain = new Chain<K, L>();
        chain.pipes = Collections.<Pipe<?, ?>>singletonList(pipe);;
        return chain;
    }

    public <V> Chain<S, V> append(Pipe<T, V> pipe) {
        Chain<S, V> chain = new Chain<S, V>();
        chain.pipes = new ArrayList<Pipe<?, ?>>(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<String, Integer> pipe1 = new Pipe<String, Integer>() {
            @Override
            public Integer transform(String s) {
                return Integer.valueOf(s);
            }
        };
        Pipe<Integer, Long> pipe2 = new Pipe<Integer, Long>() {
            @Override
            public Long transform(Integer s) {
                return s.longValue();
            }
        };
        Pipe<Long, BigInteger> pipe3 = new Pipe<Long, BigInteger>() {
            @Override
            public BigInteger transform(Long s) {
                return new BigInteger(s.toString());
            }
        };
        Chain<String, BigInteger> chain = Chain.start(pipe1).append(pipe2).append(pipe3);
        BigInteger result = chain.run("12");
        System.out.println(result);
    }
}

这篇关于Java泛型:将泛型函数对象链接在一起的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆