From 684b2e219e60a03c8ca541e84688c0b682d896e0 Mon Sep 17 00:00:00 2001 From: Adelya <65678470+Adelechka@users.noreply.github.com> Date: Sat, 1 Jun 2024 05:26:46 +0300 Subject: [PATCH] feat: Function composition (#2954) * feature: Implement Virtual Proxy pattern #2940 * feature: Implement Virtual Proxy pattern #2940 * feature: Implement Virtual Proxy pattern #2940 * feature: Implement Virtual Proxy pattern #2940 * feature: Implement Virtual Proxy pattern #2940 * feature: Implement Virtual Proxy pattern, tests added * feature: Implement Virtual Proxy pattern, tests added * feature: Implement Virtual Proxy pattern, tests added * feature: Implement Virtual Proxy pattern, tests added * feature: Implement Virtual Proxy pattern, tests added * feature: Implement function composition pattern #2897 * task: isolate virtual proxy pattern * task: isolate virtual proxy pattern * refactoring: readme.md --- function-composition/.gitignore | 59 ++++++++++ function-composition/README.md | 109 ++++++++++++++++++ .../etc/function.composition.urm.png | Bin 0 -> 16599 bytes .../etc/function.composition.urm.puml | 21 ++++ function-composition/pom.xml | 67 +++++++++++ .../iluwatar/function/composition/App.java | 50 ++++++++ .../composition/FunctionComposer.java | 46 ++++++++ .../function/composition/AppTest.java | 40 +++++++ .../composition/FunctionComposerTest.java | 102 ++++++++++++++++ pom.xml | 1 + 10 files changed, 495 insertions(+) create mode 100644 function-composition/.gitignore create mode 100644 function-composition/README.md create mode 100644 function-composition/etc/function.composition.urm.png create mode 100644 function-composition/etc/function.composition.urm.puml create mode 100644 function-composition/pom.xml create mode 100644 function-composition/src/main/java/com/iluwatar/function/composition/App.java create mode 100644 function-composition/src/main/java/com/iluwatar/function/composition/FunctionComposer.java create mode 100644 function-composition/src/test/java/com/iluwatar/function/composition/AppTest.java create mode 100644 function-composition/src/test/java/com/iluwatar/function/composition/FunctionComposerTest.java diff --git a/function-composition/.gitignore b/function-composition/.gitignore new file mode 100644 index 000000000..431eba612 --- /dev/null +++ b/function-composition/.gitignore @@ -0,0 +1,59 @@ +################## Eclipse ###################### +target +.metadata +.settings +.classpath +.project +*.class +tmp/ +*.tmp +*.bak +*~.nib +local.properties +.loadpath +.recommenders +.DS_Store + +####### Java annotation processor (APT) ######## +.factorypath + +################ Package Files ################## +*.jar +*.war +*.ear +*.swp +datanucleus.log +/bin/ +*.log +event-sourcing/Journal.json + +################## Checkstyle ################### +.checkstyle + +##################### STS ####################### +.apt_generated +.springBeans +.sts4-cache + +################# IntelliJ IDEA ################# +.idea +*.iws +*.iml +*.ipr + +################### NetBeans #################### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +#################### VS Code #################### +.vscode/ + +#################### Java Design Patterns ####### +etc/Java Design Patterns.urm.puml +serialized-entity/output.txt diff --git a/function-composition/README.md b/function-composition/README.md new file mode 100644 index 000000000..99b7b9ff2 --- /dev/null +++ b/function-composition/README.md @@ -0,0 +1,109 @@ +--- +title: Function Composition +category: Behavioral +language: en +tag: + - Functional Programming + - Functional decomposition + - Java +--- + +## Also known as + +Functional Composition + +## Intent +To enable creating complex functions by composing simpler ones, enhancing modularity and reusability of function-based logic. + +## Explanation + +Real-world example: + +> In financial software, functions that calculate various financial metrics can be composed to provide detailed analysis. For instance, a function that calculates interest can be composed with another that adjusts for taxes, allowing for a modular yet comprehensive financial assessment tool. + +In plain words: + +> The Function Composer pattern allows building complex functions by combining simpler ones, making it easier to manage, test, and reuse individual pieces of functionality. + +Wikipedia says: + +> Function composition is an act or mechanism to combine simple functions to build more complicated ones. Like the usual composition of functions in mathematics, the result of each function is passed as the argument of the next, and the result of the last one is the result of the whole. + +**Programmatic Example** + +Here is how the Function Composer pattern might be implemented and used in Java: + +```java +public class FunctionComposer { + + public static Function composeFunctions(Function f1, Function f2) { + return f1.andThen(f2); + } +} +``` +```java +public class App { + public static void main(String[] args) { + Function timesTwo = x -> x * 2; + Function square = x -> x * x; + + Function composedFunction = FunctionComposer.composeFunctions(timesTwo, square); + + int result = composedFunction.apply(3); + logger.info("Result of composing 'timesTwo' and 'square' functions applied to 3 is: " + result); + } +} +``` + +Result: +``` +Result of composing 'timesTwo' and 'square' functions applied to 3 is: 36 // Result will be 36 (3 * 2 = 6, 6 * 6 = 36) +``` + +Use ``.compose()`` function when you need pre-compose and ``.andThen()`` function when you need post-compose. + +## Sequence diagram + +![Functional Composer Diagram](./etc/function.composition.urm.png "function composition") + +## Applicability + +Use the Function Composer pattern when: + +* You want to create a pipeline of operations where the output of one function is the input to another. +* You need to enhance the clarity and quality of your code by structuring complex function logic into simpler, reusable components. +* You are working in a functional programming environment or a language that supports higher-order functions. + +## Tutorials + +[Function Composition in Java](https://functionalprogramming.medium.com/function-composition-in-java-beaf39426f52) + +## Known uses + +* Stream processing in Java 8 and above +* Query builders in ORM libraries +* Middleware composition in web frameworks + +## Consequences + +Benefits: + +* High reusability of composed functions. +* Increased modularity, making complex functions easier to understand and maintain. +* Flexible and dynamic creation of function pipelines at runtime. +* +Drawbacks: + +* Potentially higher complexity when debugging composed functions. +* Overhead from creating and managing multiple function objects in memory-intensive scenarios. + +## Related patterns + +* Chain of Responsibility +* Decorator +* Strategy + +## Credits + +[Functional Programming in Java](https://www.baeldung.com/java-functional-programming) +[Function Composition in Java](https://functionalprogramming.medium.com/function-composition-in-java-beaf39426f52) diff --git a/function-composition/etc/function.composition.urm.png b/function-composition/etc/function.composition.urm.png new file mode 100644 index 0000000000000000000000000000000000000000..53e64608631e23f24828a606f00ae9338d2f2801 GIT binary patch literal 16599 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" as F1 + +create F1 +App -> F1 : func1 = x -> x * 2 +create F1 +App -> F1 : func2 = x -> x * x + +App -> Composer : func1, func2 +activate Composer +Composer -> F1 : func1.andThen(func2) +deactivate Composer +activate F1 +F1 -> App : composedFunction +deactivate F1 + +@enduml \ No newline at end of file diff --git a/function-composition/pom.xml b/function-composition/pom.xml new file mode 100644 index 000000000..da803b723 --- /dev/null +++ b/function-composition/pom.xml @@ -0,0 +1,67 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + function-composition + + + org.junit.jupiter + junit-jupiter-engine + test + + + junit + junit + test + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + App + + + + + + + + + \ No newline at end of file diff --git a/function-composition/src/main/java/com/iluwatar/function/composition/App.java b/function-composition/src/main/java/com/iluwatar/function/composition/App.java new file mode 100644 index 000000000..da55135bd --- /dev/null +++ b/function-composition/src/main/java/com/iluwatar/function/composition/App.java @@ -0,0 +1,50 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 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.function.composition; + +import java.util.function.Function; +import org.slf4j.LoggerFactory; + +/** + * Main application class to demonstrate the use of function composition. + */ +public class App { + + /** + * Main method to demonstrate function composition using FunctionComposer. + * + * @param args command line arguments (not used) + */ + public static void main(String[] args) { + final var logger = LoggerFactory.getLogger(App.class); + Function timesTwo = x -> x * 2; + Function square = x -> x * x; + + Function composedFunction = FunctionComposer.composeFunctions(timesTwo, square); + + int result = composedFunction.apply(3); + logger.info("Result of composing 'timesTwo' and 'square' functions applied to 3 is: " + result); + } +} diff --git a/function-composition/src/main/java/com/iluwatar/function/composition/FunctionComposer.java b/function-composition/src/main/java/com/iluwatar/function/composition/FunctionComposer.java new file mode 100644 index 000000000..725903f9c --- /dev/null +++ b/function-composition/src/main/java/com/iluwatar/function/composition/FunctionComposer.java @@ -0,0 +1,46 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 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.function.composition; + +import java.util.function.Function; + +/** + * Class for composing functions using the Function Composition pattern. + * Provides a static method to compose two functions using the 'andThen' method. + */ +public class FunctionComposer { + + /** + * Composes two functions where the output of the first function becomes + * the input of the second function. + * + * @param f1 the first function to apply + * @param f2 the second function to apply after the first + * @return a composed function that applies f1 and then f2 + */ + public static Function composeFunctions(Function f1, Function f2) { + return f1.andThen(f2); + } +} diff --git a/function-composition/src/test/java/com/iluwatar/function/composition/AppTest.java b/function-composition/src/test/java/com/iluwatar/function/composition/AppTest.java new file mode 100644 index 000000000..82d543568 --- /dev/null +++ b/function-composition/src/test/java/com/iluwatar/function/composition/AppTest.java @@ -0,0 +1,40 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 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.function.composition; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +/** + * Application test + */ +class AppTest { + + @Test + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); + } +} diff --git a/function-composition/src/test/java/com/iluwatar/function/composition/FunctionComposerTest.java b/function-composition/src/test/java/com/iluwatar/function/composition/FunctionComposerTest.java new file mode 100644 index 000000000..af8950252 --- /dev/null +++ b/function-composition/src/test/java/com/iluwatar/function/composition/FunctionComposerTest.java @@ -0,0 +1,102 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 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.function.composition; + +import static org.junit.Assert.assertEquals; +import org.junit.Test; +import java.util.function.Function; + +/** + * Test class for FunctionComposer. + */ +public class FunctionComposerTest { + + /** + * Tests the composition of two functions. + */ + @Test + public void testComposeFunctions() { + Function timesTwo = x -> x * 2; + Function square = x -> x * x; + + Function composed = FunctionComposer.composeFunctions(timesTwo, square); + + assertEquals("Expected output of composed functions is 36", 36, (int) composed.apply(3)); + } + + /** + * Tests function composition with identity function. + */ + @Test + public void testComposeWithIdentity() { + Function identity = Function.identity(); + Function timesThree = x -> x * 3; + + Function composedLeft = FunctionComposer.composeFunctions(identity, timesThree); + Function composedRight = FunctionComposer.composeFunctions(timesThree, identity); + + assertEquals("Composition with identity on the left should be the same", 9, (int) composedLeft.apply(3)); + assertEquals("Composition with identity on the right should be the same", 9, (int) composedRight.apply(3)); + } + + /** + * Tests function composition resulting in zero. + */ + @Test + public void testComposeToZero() { + Function multiply = x -> x * 10; + Function toZero = x -> 0; + + Function composed = FunctionComposer.composeFunctions(multiply, toZero); + + assertEquals("Expected output of function composition leading to zero is 0", 0, (int) composed.apply(5)); + } + + /** + * Tests the composition with a negative function. + */ + @Test + public void testComposeNegative() { + Function negate = x -> -x; + Function square = x -> x * x; + + Function composed = FunctionComposer.composeFunctions(negate, square); + + assertEquals("Expected square of negative number to be positive", 9, (int) composed.apply(3)); + } + + /** + * Tests the composition of functions that cancel each other out. + */ + @Test + public void testComposeInverseFunctions() { + Function timesTwo = x -> x * 2; + Function half = x -> x / 2; + + Function composed = FunctionComposer.composeFunctions(timesTwo, half); + + assertEquals("Expect the functions to cancel each other out", 5, (int) composed.apply(5)); + } +} diff --git a/pom.xml b/pom.xml index 7e590a318..4898fa441 100644 --- a/pom.xml +++ b/pom.xml @@ -215,6 +215,7 @@ serialized-lob server-session virtual-proxy + function-composition