pipeline/README.md
The Pipeline design pattern in Java is engineered to facilitate data processing across discrete stages, enhancing modular development and operational efficiency.
Real-world example
A practical example of the Java Pipeline design pattern can be seen in assembly lines, such as those in car manufacturing, illustrating its efficiency and scalability.
In this analogy, the car manufacturing process is divided into several discrete stages, each stage handling a specific part of the car assembly. For example:
- Chassis Assembly: The base frame of the car is assembled.
- Engine Installation: The engine is installed onto the chassis.
- Painting: The car is painted.
- Interior Assembly: The interior, including seats and dashboard, is installed.
- Quality Control: The finished car is inspected for defects.
In the Java Pipeline pattern, each stage functions independently and sequentially, ensuring smooth data flow and easy modifications. The output of one stage (e.g., a partially assembled car) becomes the input for the next stage. This modular approach allows for easy maintenance, scalability (e.g., adding more workers to a stage), and flexibility (e.g., replacing a stage with a more advanced version). Just like in a software pipeline, changes in one stage do not affect the others, facilitating continuous improvements and efficient production.
In plain words
Pipeline pattern is an assembly line where partial results are passed from one stage to another.
Wikipedia says
In software engineering, a pipeline consists of a chain of processing elements (processes, threads, coroutines, functions, etc.), arranged so that the output of each element is the input of the next; the name is by analogy to a physical pipeline.
Flowchart
Let's create a string processing pipeline example. The stages of our pipeline are called Handlers.
interface Handler<I, O> {
O process(I input);
}
In our string processing example we have 3 different concrete Handlers.
class RemoveAlphabetsHandler implements Handler<String, String> {
// ...
}
class RemoveDigitsHandler implements Handler<String, String> {
// ...
}
class ConvertToCharArrayHandler implements Handler<String, char[]> {
// ...
}
Here is the Pipeline that will gather and execute the handlers one by one.
class Pipeline<I, O> {
private final Handler<I, O> currentHandler;
Pipeline(Handler<I, O> currentHandler) {
this.currentHandler = currentHandler;
}
<K> Pipeline<I, K> addHandler(Handler<O, K> newHandler) {
return new Pipeline<>(input -> newHandler.process(currentHandler.process(input)));
}
O execute(I input) {
return currentHandler.process(input);
}
}
And here's the Pipeline in action processing the string.
public static void main(String[] args) {
LOGGER.info("Creating pipeline");
var filters = new Pipeline<>(new RemoveAlphabetsHandler())
.addHandler(new RemoveDigitsHandler())
.addHandler(new ConvertToCharArrayHandler());
var input = "GoYankees123!";
LOGGER.info("Executing pipeline with input: {}", input);
var output = filters.execute(input);
LOGGER.info("Pipeline output: {}", output);
}
Console output:
07:34:27.069 [main] INFO com.iluwatar.pipeline.App -- Creating pipeline
07:34:27.072 [main] INFO com.iluwatar.pipeline.App -- Executing pipeline with input: GoYankees123!
07:34:27.074 [main] INFO com.iluwatar.pipeline.RemoveAlphabetsHandler -- Current handler: class com.iluwatar.pipeline.RemoveAlphabetsHandler, input is GoYankees123! of type class java.lang.String, output is 123!, of type class java.lang.String
07:34:27.075 [main] INFO com.iluwatar.pipeline.RemoveDigitsHandler -- Current handler: class com.iluwatar.pipeline.RemoveDigitsHandler, input is 123! of type class java.lang.String, output is !, of type class java.lang.String
07:34:27.075 [main] INFO com.iluwatar.pipeline.ConvertToCharArrayHandler -- Current handler: class com.iluwatar.pipeline.ConvertToCharArrayHandler, input is ! of type class java.lang.String, output is [!], of type class [Ljava.lang.Character;
07:34:27.075 [main] INFO com.iluwatar.pipeline.App -- Pipeline output: [!]
Use the Pipeline pattern when you want to
Benefits:
Trade-offs: