preface
Pipeline design pattern will not say, here to write a very simple implementation, as follows.
public interface Step<I.O> {
static <I, O> Step<I, O> of(Step<I, O> step) {
return step;
}
default <R> Step<I, R> addStep(Step<O, R> source) {
return value -> source.execute(execute(value));
}
O execute(I value);
}
Copy the code
That’s it. So let’s see how it works.
public class Main {
private static String test(Integer a) {
System.out.println(Perform the test "");
return "1";
}
private static Long test2(String a) {
System.out.println("Executive test2");
return 1l;
}
public static void main(String[] args) {
Step<Integer, Long> step = Step.of(Main::test)
.addStep(Main::test2);
step.execute(1);
}
Copy the code
This is a piece of code that goes from an input of type Integer to the output of a Long result.
There are a few tricky points here, like the one below.
default <R> Step<I, R> addStep(Step<O, R> source) {
return value -> source.execute(execute(value));
}
Copy the code
This is the method of adding steps on the assembly line, we are already in the Step class defines the generic I and O, I said the type of input and output type, O said the first implementation classes have to identify the type of input and output, such as we use the method reference above, tell the type of the first input is an Integer, the output is of type String, Then when you add a “step”, the input type can only be the output type of the previous step, and define an R generic to indicate that the output type of the newly added “step” is R.
Look at the following paragraph.
return value -> source.execute(execute(value));
Copy the code
This is actually the same thing as this, just lambda notation, which is a little bit cleaner.
return new Step<I, R>() {
@Override
public R execute(I value) {
return source.execute(Step.this.execute(value)); }};Copy the code