Java流水线Pipeline设计模式

Pipeline模式适用于流式递归传递输入和处理后的输出,对于比较简单的场景,使用Java函数接口是
首页 新闻资讯 行业资讯 Java流水线Pipeline设计模式

概述

管道模式背后的主要思想是创建一组操作(管道)并通过它传递数据。跟责任链和装饰器模式相比,Pipeline的主要优势在于它对结果的类型具有灵活性。

管道可以处理任何类型的输入和输出。

不可变管道

让我们创建一个不可变的管道的例子。从管道接口开始:

publicinterface Pipe<IN,OUT>{OUTprocess(INinput);}

这是一个非常简单的接口,只有一个方法,它接受输入并产生输出。接口是参数化的,我们可以在其中提供任何实现。

现在,让我们创建一个管道类:

publicclass Pipeline<IN,OUT>{

    private Collection<Pipe<?,?>>pipes;private Pipeline(Pipe<IN,OUT>pipe){
        pipes=Collections.singletonList(pipe);}

    private Pipeline(Collection<Pipe<?,?>>pipes){
        this.pipes=new ArrayList<>(pipes);}publicstatic<IN,OUT>Pipeline<IN,OUT>of(Pipe<IN,OUT>pipe){returnnew Pipeline<>(pipe);}public<NEW_OUT>Pipeline<IN,NEW_OUT>withNextPipe(Pipe<OUT,NEW_OUT>pipe){
        final ArrayList<Pipe<?,?>>newPipes=new ArrayList<>(pipes);newPipes.add(pipe);returnnew Pipeline<>(newPipes);}publicOUTprocess(INinput){
        Object output=input;for(final Pipe pipe : pipes){
            output=pipe.process(output);}return(OUT)output;}
}

因为我们需要一个类型安全级别,并且不允许使管道失效,所以在添加新管道时,将产生一个新的独立管道。

简单管道

我们可以稍微简化上面的例子,并完全去掉Pipeline类:

publicinterface Pipe<IN,OUT>{OUTprocess(INinput);default<NEW_OUT>Pipe<IN,NEW_OUT>add(Pipe<OUT,NEW_OUT>pipe){returninput->pipe.process(process(input));}
}

与以前使用管道的实现相比,此解决方案非常简单和灵活。

改进

我们可以用现有的Function接口替代它:

publicinterfaceFunction<T,R>{//...Rapply(T t);//...}

此外,Function接口包含两个有用的方法,其中一个是andThen:

default<V>Function<T,V>andThen(Function<? super R,? extends V>after){
    Objects.requireNonNull(after);return(T t)->after.apply(apply(t));}

我们可以使用它来代替以前的add方法。此外,Function接口提供了一种在管道开始时添加函数的方法:

default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
    Objects.requireNonNull(before);
    return (V v) -> apply(before.apply(v));
}

通过使用Function,我们可以创建非常灵活和易于使用的管道:

@Testvoid whenCombiningThreeFunctions_andInitializingPipeline_thenResultIsCorrect(){Function<Integer,Integer>square=s->s*s;Function<Integer,Integer>half=s->s/2;Function<Integer,String>toString=Object::toString;Function<Integer,String>pipeline=square.andThen(half).andThen(toString);String result=pipeline.apply(5);String expected="12";assertEquals(expected,result);}

我们可以使用BiFunctions扩展管道:

@Testvoid whenCombiningFunctionAndBiFunctions_andInitializingPipeline_thenResultIsCorrect(){
    BiFunction<Integer,Integer,Integer>add=Integer::sum;BiFunction<Integer,Integer,Integer>mul=(a,b)->a*b;Function<Integer,String>toString=Object::toString;BiFunction<Integer,Integer,String>pipeline=add.andThen(a->mul.apply(a,2)).andThen(toString);String result=pipeline.apply(1,2);String expected="6";assertEquals(expected,result);}

因为andThen方法采用Function,所以我们必须将mul BiFunction转换为一个Function。

结论

Pipeline模式适用于流式递归传递输入和处理后的输出,对于比较简单的场景,使用Java函数接口是挺不错的选项。

30    2023-05-10 15:08:00    Pipeline 设计 模式