diff --git a/pom.xml b/pom.xml index 66c5fa850..7e669d396 100644 --- a/pom.xml +++ b/pom.xml @@ -147,13 +147,13 @@ event-sourcing data-transfer-object throttling - unit-of-work partial-response eip-wire-tap eip-splitter eip-aggregator retry + trampoline diff --git a/trampoline/.gitignore b/trampoline/.gitignore new file mode 100644 index 000000000..431845ed0 --- /dev/null +++ b/trampoline/.gitignore @@ -0,0 +1,2 @@ +/target/ +.idea/ diff --git a/trampoline/README.md b/trampoline/README.md new file mode 100644 index 000000000..cae343a61 --- /dev/null +++ b/trampoline/README.md @@ -0,0 +1,45 @@ +--- +layout: pattern +title: Trampoline +folder: trampoline +permalink: /patterns/trampoline/ +categories: Behavior +tags: + - Java + - Difficulty-Intermediate + - Performance + - Recursion +--- + +## Intent +Trampoline pattern is used for implementing algorithms recursively in Java without blowing the stack +and to interleave the execution of functions without hard coding them together +It is possible by representing a computation in one of 2 states : done | more +(completed with result, or a reference to the reminder of the computation, +something like the way a java.util.Supplier does). + + +## Explanation +Trampoline pattern allows to define recursive algorithms by iterative loop. + + +## Applicability +Use the Trampoline pattern when + +* For implementing tail recursive function. This pattern allows to switch on a stackless operation. +* For interleaving the execution of two or more functions on the same thread. + +## Known uses(real world examples) +* Trampoline refers to using reflection to avoid using inner classes, for example in event listeners. +The time overhead of a reflection call is traded for the space overhead of an inner class. +Trampolines in Java usually involve the creation of a GenericListener to pass events to an outer class. + + +## Tutorials +* [Trampolining: a practical guide for awesome Java Developers](https://medium.com/@johnmcclean/trampolining-a-practical-guide-for-awesome-java-developers-4b657d9c3076) +* [Trampoline in java ](http://mindprod.com/jgloss/trampoline.html) + +## Credits +* [library 'cyclops-react' uses the pattern](https://github.com/aol/cyclops-react) + + diff --git a/trampoline/pom.xml b/trampoline/pom.xml new file mode 100644 index 000000000..71de3f8f2 --- /dev/null +++ b/trampoline/pom.xml @@ -0,0 +1,77 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.19.0-SNAPSHOT + + + trampoline + + + junit + junit + 4.12 + test + + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + + org.projectlombok + lombok + 1.16.18 + + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.19 + + false + + + + + diff --git a/trampoline/src/main/java/com/iluwatar/trampoline/Trampoline.java b/trampoline/src/main/java/com/iluwatar/trampoline/Trampoline.java new file mode 100644 index 000000000..277ae9ffb --- /dev/null +++ b/trampoline/src/main/java/com/iluwatar/trampoline/Trampoline.java @@ -0,0 +1,85 @@ +package com.iluwatar.trampoline; + +import java.util.stream.Stream; + +/** + *

Trampoline pattern allows to define recursive algorithms by iterative loop

+ *

When get is called on the returned Trampoline, internally it will iterate calling ‘jump’ + * on the returned Trampoline as long as the concrete instance returned is {@link #more(Trampoline)}, + * stopping once the returned instance is {@link #done(Object)}.

+ *

Essential we convert looping via recursion into iteration, + * the key enabling mechanism is the fact that {@link #more(Trampoline)} is a lazy operation.

+ * + * @param is type for returning result. + */ +public interface Trampoline { + T get(); + + + /** + * @return next stage + */ + default Trampoline jump() { + return this; + } + + + default T result() { + return get(); + } + + /** + * @return true if complete + */ + default boolean complete() { + return true; + } + + /** + * Created a completed Trampoline + * + * @param result Completed result + * @return Completed Trampoline + */ + static Trampoline done(final T result) { + return () -> result; + } + + + /** + * Create a Trampoline that has more work to do + * + * @param trampoline Next stage in Trampoline + * @return Trampoline with more work + */ + static Trampoline more(final Trampoline> trampoline) { + return new Trampoline() { + @Override + public boolean complete() { + return false; + } + + @Override + public Trampoline jump() { + return trampoline.result(); + } + + @Override + public T get() { + return trampoline(this); + } + + T trampoline(final Trampoline trampoline) { + + return Stream.iterate(trampoline, Trampoline::jump) + .filter(Trampoline::complete) + .findFirst() + .get() + .result(); + + } + }; + } + + +} diff --git a/trampoline/src/main/java/com/iluwatar/trampoline/TrampolineApp.java b/trampoline/src/main/java/com/iluwatar/trampoline/TrampolineApp.java new file mode 100644 index 000000000..76e3ed3da --- /dev/null +++ b/trampoline/src/main/java/com/iluwatar/trampoline/TrampolineApp.java @@ -0,0 +1,58 @@ +/** + * The MIT License + * Copyright (c) 2014-2016 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.trampoline; + + +import lombok.extern.slf4j.Slf4j; + +/** + *

Trampoline pattern allows to define recursive algorithms by iterative loop

+ *

it is possible to implement algorithms recursively in Java without blowing the stack + * and to interleave the execution of functions without hard coding them together or even using threads.

+ */ +@Slf4j +public class TrampolineApp { + + /** + * Main program for showing pattern. It does loop with factorial function. + * */ + public static void main(String[] args) { + log.info("start pattern"); + Integer result = loop(10, 1).result(); + log.info("result {}", result); + + } + + /** + * Manager for pattern. Define it with a factorial function. + */ + public static Trampoline loop(int times, int prod) { + if (times == 0) { + return Trampoline.done(prod); + } else { + return Trampoline.more(() -> loop(times - 1, prod * times)); + } + } + +} diff --git a/trampoline/src/test/java/com/iluwatar/trampoline/TrampolineAppTest.java b/trampoline/src/test/java/com/iluwatar/trampoline/TrampolineAppTest.java new file mode 100644 index 000000000..553e583e1 --- /dev/null +++ b/trampoline/src/test/java/com/iluwatar/trampoline/TrampolineAppTest.java @@ -0,0 +1,22 @@ +package com.iluwatar.trampoline; + +import org.junit.Test; + +import java.io.IOException; + +import static org.junit.Assert.*; + + +/** + * Test for trampoline pattern. + * */ +public class TrampolineAppTest { + + + @Test + public void testTrampolineWithFactorialFunction() throws IOException { + int result = TrampolineApp.loop(10, 1).result(); + assertEquals("Be equal", 3628800, result); + } + +} \ No newline at end of file