#564: Collection Pipeline pattern

This commit is contained in:
nikhilbarar 2018-07-02 00:42:04 +05:30
parent 987994f0fe
commit 2c8d1744df
11 changed files with 490 additions and 0 deletions

View File

@ -0,0 +1,29 @@
---
layout: pattern
title: Collection Pipeline
folder: collection-pipeline
permalink: /patterns/collection-pipeline/
categories: Functional
tags:
- Java
- Difficulty-Beginner
- Functional
---
## Intent
Collection Pipeline introduces Function Composition and Collection Pipeline, two functional-style patterns that you can combine to iterate collections in your code.
In functional programming, it's common to sequence complex operations through a series of smaller modular functions or operations. The series is called a composition of functions, or a function composition. When a collection of data flows through a function composition, it becomes a collection pipeline. Function Composition and Collection Pipeline are two design patterns frequently used in functional-style programming.
![alt text](./etc/collection-pipeline.png "Collection Pipeline")
## Applicability
Use the Collection Pipeline pattern when
* When you want to perform a sequence of operations where one operation's collected output is fed into the next
* When you use a lot of statements in your code
* When you use a lot of loops in your code
## Credits
* [Function composition and the Collection Pipeline pattern](https://www.ibm.com/developerworks/library/j-java8idioms2/index.html)
* [Martin Fowler](https://martinfowler.com/articles/collection-pipeline/)

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<class-diagram version="1.2.2" icons="true" always-add-relationships="false" generalizations="true" realizations="true"
associations="true" dependencies="false" nesting-relationships="true" router="FAN">
<class id="1" language="java" name="com.iluwatar.collectionpipeline.App" project="collection-pipeline"
file="/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/App.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="952" y="278"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="2" language="java" name="com.iluwatar.collectionpipeline.ImperativeProgramming"
project="collection-pipeline"
file="/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/ImperativeProgramming.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="552" y="107"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="3" language="java" name="com.iluwatar.collectionpipeline.Car" project="collection-pipeline"
file="/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/Car.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="476" y="301"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="4" language="java" name="com.iluwatar.collectionpipeline.FunctionalProgramming"
project="collection-pipeline"
file="/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/FunctionalProgramming.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="914" y="105"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="5" language="java" name="com.iluwatar.collectionpipeline.Iterating" project="collection-pipeline"
file="/collection-pipeline/src/main/java/com/iluwatar/collectionpipeline/Iterating.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="723" y="280"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</classifier-display>
<association-display labels="true" multiplicity="true"/>
</class-diagram>

View File

@ -0,0 +1,45 @@
<!--
The MIT License
Copyright (c) 2014 Ilkka Seppälä
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.iluwatar</groupId>
<artifactId>java-design-patterns</artifactId>
<version>1.20.0-SNAPSHOT</version>
</parent>
<artifactId>collection-pipeline</artifactId>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,60 @@
/**
* The MIT License
* Copyright (c) 2014 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.collectionpipeline;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* In imperative-style programming, it is common to use for and while loops for
* most kinds of data processing. Function composition is a simple technique
* that lets you sequence modular functions to create more complex operations.
* When you run data through the sequence, you have a collection pipeline.
* Together, the Function Composition and Collection Pipeline patterns enable
* you to create sophisticated programs where data flow from upstream to
* downstream and is passed through a series of transformations.
*
*/
public class App {
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
/**
* Program entry point.
*
* @param args
* command line args
*/
public static void main(String[] args) {
List<Car> cars = Iterating.createCars();
List<String> modelsImperative = ImperativeProgramming.getModelsAfter2000UsingFor(cars);
LOGGER.info(modelsImperative.toString());
List<String> modelsFunctional = FunctionalProgramming.getModelsAfter2000UsingPipeline(cars);
LOGGER.info(modelsFunctional.toString());
}
}

View File

@ -0,0 +1,56 @@
/**
* The MIT License
* Copyright (c) 2014 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.collectionpipeline;
/**
* A Car class that has the properties of make, model, and year.
*/
public class Car {
private String make;
private String model;
private int year;
/**
* Constructor to create an instance of car.
* @param theMake the make of the car
* @param theModel the model of the car
* @param yearOfMake the year of built of the car
*/
public Car(String theMake, String theModel, int yearOfMake) {
make = theMake;
model = theModel;
year = yearOfMake;
}
public String getMake() {
return make;
}
public String getModel() {
return model;
}
public int getYear() {
return year;
}
}

View File

@ -0,0 +1,61 @@
/**
* The MIT License
* Copyright (c) 2014 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.collectionpipeline;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
* Iterating and sorting with a collection pipeline
*
* <p>In functional programming, it's common to sequence complex operations through
* a series of smaller modular functions or operations. The series is called a
* composition of functions, or a function composition. When a collection of
* data flows through a function composition, it becomes a collection pipeline.
* Function Composition and Collection Pipeline are two design patterns
* frequently used in functional-style programming.
*
* <p>Instead of passing a lambda expression to the map method, we passed the
* method reference Car::getModel. Likewise, instead of passing the lambda
* expression car -> car.getYear() to the comparing method, we passed the method
* reference Car::getYear. Method references are short, concise, and expressive.
* It is best to use them wherever possible.
*
*/
public class FunctionalProgramming {
private FunctionalProgramming() {
}
/**
* Method to get models using for collection pipeline.
*
* @param cars {@link List} of {@link Car} to be used for filtering
* @return {@link List} of {@link String} representing models built after year 2000
*/
public static List<String> getModelsAfter2000UsingPipeline(List<Car> cars) {
return cars.stream().filter(car -> car.getYear() > 2000)
.sorted(Comparator.comparing(Car::getYear))
.map(Car::getModel).collect(Collectors.toList());
}
}

View File

@ -0,0 +1,80 @@
/**
* The MIT License
* Copyright (c) 2014 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.collectionpipeline;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* Imperative-style programming to iterate over the list and get the names of
* cars made later than the year 2000. We then sort the models in ascending
* order by year.
*
* <p>As you can see, there's a lot of looping in this code. First, the
* getModelsAfter2000UsingFor method takes a list of cars as its parameter. It
* extracts or filters out cars made after the year 2000, putting them into a
* new list named carsSortedByYear. Next, it sorts that list in ascending order
* by year-of-make. Finally, it loops through the list carsSortedByYear to get
* the model names and returns them in a list.
*
* <p>This short example demonstrates what I call the effect of statements. While
* functions and methods in general can be used as expressions, the {@link Collections}
* sort method doesn't return a result. Because it is used as a statement, it
* mutates the list given as argument. Both of the for loops also mutate lists
* as they iterate. Being statements, that's just how these elements work. As a
* result, the code contains unnecessary garbage variables
*/
public class ImperativeProgramming {
private ImperativeProgramming() {
}
/**
* Method to return the car models built after year 2000 using for loops.
* @param cars {@link List} of {@link Car} to iterate over
* @return {@link List} of {@link String} of car models built after year 2000
*/
public static List<String> getModelsAfter2000UsingFor(List<Car> cars) {
List<Car> carsSortedByYear = new ArrayList<>();
for (Car car : cars) {
if (car.getYear() > 2000) {
carsSortedByYear.add(car);
}
}
Collections.sort(carsSortedByYear, new Comparator<Car>() {
public int compare(Car car1, Car car2) {
return new Integer(car1.getYear()).compareTo(car2.getYear());
}
});
List<String> models = new ArrayList<>();
for (Car car : carsSortedByYear) {
models.add(car.getModel());
}
return models;
}
}

View File

@ -0,0 +1,46 @@
/**
* The MIT License
* Copyright (c) 2014 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.collectionpipeline;
import java.util.Arrays;
import java.util.List;
/**
* A factory class to create a collection of {@link Car} instances.
*/
public class Iterating {
private Iterating() {
}
/**
* Factory method to create a {@link List} of {@link Car} instances.
* @return {@link List} of {@link Car}
*/
public static List<Car> createCars() {
return Arrays.asList(new Car("Jeep", "Wrangler", 2011), new Car("Jeep", "Comanche", 1990),
new Car("Dodge", "Avenger", 2010),
new Car("Buick", "Cascada", 2016),
new Car("Ford", "Focus", 2012),
new Car("Chevrolet", "Geo Metro", 1992));
}
}

View File

@ -0,0 +1,50 @@
/**
* The MIT License
* Copyright (c) 2014 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.collectionpipeline;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.Test;
/**
* Tests that Collection Pipeline methods work as expected.
*/
public class AppTest {
private List<Car> cars = Iterating.createCars();
@Test
public void testGetModelsAfter2000UsingFor() {
List<String> models = ImperativeProgramming.getModelsAfter2000UsingFor(cars);
assertEquals(models, Arrays.asList("Avenger", "Wrangler", "Focus", "Cascada"));
}
@Test
public void testGetModelsAfter2000UsingPipeline() {
List<String> models = FunctionalProgramming.getModelsAfter2000UsingPipeline(cars);
assertEquals(models, Arrays.asList("Avenger", "Wrangler", "Focus", "Cascada"));
}
}

View File

@ -161,6 +161,7 @@
<module>dirty-flag</module>
<module>trampoline</module>
<module>serverless</module>
<module>collection-pipeline</module>
</modules>
<repositories>