diff --git a/abstract-factory/README.md b/abstract-factory/README.md index a08cbd35c..423988b58 100644 --- a/abstract-factory/README.md +++ b/abstract-factory/README.md @@ -179,10 +179,15 @@ Use the Abstract Factory pattern when * Dependency injection in java hides the service class dependencies that can lead to runtime errors that would have been caught at compile time. + +## Tutorial +* [Abstract Factory Pattern Tutorial](https://www.journaldev.com/1418/abstract-factory-design-pattern-in-java) + ## Presentations * [Abstract Factory Pattern](etc/presentation.html) + ## Real world examples * [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html) diff --git a/bridge/README.md b/bridge/README.md index 882640725..bce723971 100644 --- a/bridge/README.md +++ b/bridge/README.md @@ -188,6 +188,9 @@ Use the Bridge pattern when * you have a proliferation of classes. Such a class hierarchy indicates the need for splitting an object into two parts. Rumbaugh uses the term "nested generalizations" to refer to such class hierarchies * you want to share an implementation among multiple objects (perhaps using reference counting), and this fact should be hidden from the client. A simple example is Coplien's String class, in which multiple objects can share the same string representation. +## Tutorial +* [Bridge Pattern Tutorial](https://www.journaldev.com/1491/bridge-design-pattern-java) + ## Credits * [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/decorator/README.md b/decorator/README.md index 4b6bfe61f..dcf49dbf5 100644 --- a/decorator/README.md +++ b/decorator/README.md @@ -116,6 +116,9 @@ Use Decorator * For responsibilities that can be withdrawn * When extension by subclassing is impractical. Sometimes a large number of independent extensions are possible and would produce an explosion of subclasses to support every combination. Or a class definition may be hidden or otherwise unavailable for subclassing +## Tutorial +* [Decorator Pattern Tutorial](https://www.journaldev.com/1540/decorator-design-pattern-in-java-example) + ## Real world examples * [java.io.InputStream](http://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html), [java.io.OutputStream](http://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html), [java.io.Reader](http://docs.oracle.com/javase/8/docs/api/java/io/Reader.html) and [java.io.Writer](http://docs.oracle.com/javase/8/docs/api/java/io/Writer.html) diff --git a/interpreter/src/test/java/com/iluwatar/interpreter/ExpressionTest.java b/interpreter/src/test/java/com/iluwatar/interpreter/ExpressionTest.java index a3d9f21f2..a9a4f11d8 100644 --- a/interpreter/src/test/java/com/iluwatar/interpreter/ExpressionTest.java +++ b/interpreter/src/test/java/com/iluwatar/interpreter/ExpressionTest.java @@ -23,6 +23,7 @@ package com.iluwatar.interpreter; import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -43,6 +44,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; * @param Type of Expression * @author Jeroen Meulemeester */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public abstract class ExpressionTest { /** @@ -88,6 +90,13 @@ public abstract class ExpressionTest { this.factory = factory; } + /** + * Create a new set of test entries with the expected result + * + * @return The list of parameters used during this test + */ + public abstract Stream expressionProvider(); + /** * Verify if the expression calculates the correct result when calling {@link E#interpret()} */ diff --git a/interpreter/src/test/java/com/iluwatar/interpreter/MinusExpressionTest.java b/interpreter/src/test/java/com/iluwatar/interpreter/MinusExpressionTest.java index eab0ea011..276b934c3 100644 --- a/interpreter/src/test/java/com/iluwatar/interpreter/MinusExpressionTest.java +++ b/interpreter/src/test/java/com/iluwatar/interpreter/MinusExpressionTest.java @@ -38,7 +38,8 @@ public class MinusExpressionTest extends ExpressionTest { * * @return The list of parameters used during this test */ - public static Stream expressionProvider() { + @Override + public Stream expressionProvider() { return prepareParameters((f, s) -> f - s); } diff --git a/interpreter/src/test/java/com/iluwatar/interpreter/MultiplyExpressionTest.java b/interpreter/src/test/java/com/iluwatar/interpreter/MultiplyExpressionTest.java index 6e5384f8b..e5f4e61ee 100644 --- a/interpreter/src/test/java/com/iluwatar/interpreter/MultiplyExpressionTest.java +++ b/interpreter/src/test/java/com/iluwatar/interpreter/MultiplyExpressionTest.java @@ -38,7 +38,8 @@ public class MultiplyExpressionTest extends ExpressionTest { * * @return The list of parameters used during this test */ - public static Stream expressionProvider() { + @Override + public Stream expressionProvider() { return prepareParameters((f, s) -> f * s); } diff --git a/interpreter/src/test/java/com/iluwatar/interpreter/NumberExpressionTest.java b/interpreter/src/test/java/com/iluwatar/interpreter/NumberExpressionTest.java index 698da52bc..cc7c82e7e 100644 --- a/interpreter/src/test/java/com/iluwatar/interpreter/NumberExpressionTest.java +++ b/interpreter/src/test/java/com/iluwatar/interpreter/NumberExpressionTest.java @@ -42,7 +42,8 @@ public class NumberExpressionTest extends ExpressionTest { * * @return The list of parameters used during this test */ - public static Stream expressionProvider() { + @Override + public Stream expressionProvider() { return prepareParameters((f, s) -> f); } diff --git a/interpreter/src/test/java/com/iluwatar/interpreter/PlusExpressionTest.java b/interpreter/src/test/java/com/iluwatar/interpreter/PlusExpressionTest.java index ae2423c7a..9687b5399 100644 --- a/interpreter/src/test/java/com/iluwatar/interpreter/PlusExpressionTest.java +++ b/interpreter/src/test/java/com/iluwatar/interpreter/PlusExpressionTest.java @@ -38,7 +38,8 @@ public class PlusExpressionTest extends ExpressionTest { * * @return The list of parameters used during this test */ - public static Stream expressionProvider() { + @Override + public Stream expressionProvider() { return prepareParameters((f, s) -> f + s); } diff --git a/object-mother/src/main/java/com/iluwatar/objectmother/RoyaltyObjectMother.java b/object-mother/src/main/java/com/iluwatar/objectmother/RoyaltyObjectMother.java index 118253d56..633a95b71 100644 --- a/object-mother/src/main/java/com/iluwatar/objectmother/RoyaltyObjectMother.java +++ b/object-mother/src/main/java/com/iluwatar/objectmother/RoyaltyObjectMother.java @@ -28,7 +28,7 @@ package com.iluwatar.objectmother; public final class RoyaltyObjectMother { /** - * Method to create a sober and unhappy king. The standard paramters are set. + * Method to create a sober and unhappy king. The standard parameters are set. * @return An instance of {@link com.iluwatar.objectmother.King} with the standard properties. */ public static King createSoberUnhappyKing() { diff --git a/observer/src/test/java/com/iluwatar/observer/HobbitsTest.java b/observer/src/test/java/com/iluwatar/observer/HobbitsTest.java index 21e4acd44..8bad7f59e 100644 --- a/observer/src/test/java/com/iluwatar/observer/HobbitsTest.java +++ b/observer/src/test/java/com/iluwatar/observer/HobbitsTest.java @@ -33,7 +33,8 @@ import java.util.List; */ public class HobbitsTest extends WeatherObserverTest { - static Collection dataProvider() { + @Override + public Collection dataProvider() { final List testData = new ArrayList<>(); testData.add(new Object[]{WeatherType.SUNNY, "The happy hobbits bade in the warm sun."}); testData.add(new Object[]{WeatherType.RAINY, "The hobbits look for cover from the rain."}); diff --git a/observer/src/test/java/com/iluwatar/observer/OrcsTest.java b/observer/src/test/java/com/iluwatar/observer/OrcsTest.java index 78667b678..2d82f86a0 100644 --- a/observer/src/test/java/com/iluwatar/observer/OrcsTest.java +++ b/observer/src/test/java/com/iluwatar/observer/OrcsTest.java @@ -33,7 +33,8 @@ import java.util.List; */ public class OrcsTest extends WeatherObserverTest { - static Collection dataProvider() { + @Override + public Collection dataProvider() { final List testData = new ArrayList<>(); testData.add(new Object[]{WeatherType.SUNNY, "The sun hurts the orcs' eyes."}); testData.add(new Object[]{WeatherType.RAINY, "The orcs are dripping wet."}); diff --git a/observer/src/test/java/com/iluwatar/observer/WeatherObserverTest.java b/observer/src/test/java/com/iluwatar/observer/WeatherObserverTest.java index da3fad1eb..4bdac3bf4 100644 --- a/observer/src/test/java/com/iluwatar/observer/WeatherObserverTest.java +++ b/observer/src/test/java/com/iluwatar/observer/WeatherObserverTest.java @@ -23,11 +23,14 @@ package com.iluwatar.observer; import com.iluwatar.observer.utils.InMemoryAppender; + +import java.util.Collection; import java.util.function.Supplier; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -39,6 +42,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; * @param Type of WeatherObserver * @author Jeroen Meulemeester */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public abstract class WeatherObserverTest { private InMemoryAppender appender; @@ -67,6 +71,8 @@ public abstract class WeatherObserverTest { this.factory = factory; } + public abstract Collection dataProvider(); + /** * Verify if the weather has the expected influence on the observer */ diff --git a/observer/src/test/java/com/iluwatar/observer/generic/GHobbitsTest.java b/observer/src/test/java/com/iluwatar/observer/generic/GHobbitsTest.java index 8d86529c7..5c67b03b7 100644 --- a/observer/src/test/java/com/iluwatar/observer/generic/GHobbitsTest.java +++ b/observer/src/test/java/com/iluwatar/observer/generic/GHobbitsTest.java @@ -35,7 +35,8 @@ import java.util.List; */ public class GHobbitsTest extends ObserverTest { - static Collection dataProvider() { + @Override + public Collection dataProvider() { final List testData = new ArrayList<>(); testData.add(new Object[]{WeatherType.SUNNY, "The happy hobbits bade in the warm sun."}); testData.add(new Object[]{WeatherType.RAINY, "The hobbits look for cover from the rain."}); diff --git a/observer/src/test/java/com/iluwatar/observer/generic/ObserverTest.java b/observer/src/test/java/com/iluwatar/observer/generic/ObserverTest.java index 0feba8ea2..7b0c65ea5 100644 --- a/observer/src/test/java/com/iluwatar/observer/generic/ObserverTest.java +++ b/observer/src/test/java/com/iluwatar/observer/generic/ObserverTest.java @@ -26,9 +26,11 @@ import com.iluwatar.observer.WeatherType; import com.iluwatar.observer.utils.InMemoryAppender; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; +import java.util.Collection; import java.util.function.Supplier; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -39,6 +41,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; * @param Type of Observer * @author Jeroen Meulemeester */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public abstract class ObserverTest { private InMemoryAppender appender; @@ -67,6 +70,8 @@ public abstract class ObserverTest { this.factory = factory; } + public abstract Collection dataProvider(); + /** * Verify if the weather has the expected influence on the observer */ diff --git a/observer/src/test/java/com/iluwatar/observer/generic/OrcsTest.java b/observer/src/test/java/com/iluwatar/observer/generic/OrcsTest.java index 95adf5a28..2ce34dbac 100644 --- a/observer/src/test/java/com/iluwatar/observer/generic/OrcsTest.java +++ b/observer/src/test/java/com/iluwatar/observer/generic/OrcsTest.java @@ -35,7 +35,8 @@ import java.util.List; */ public class OrcsTest extends ObserverTest { - static Collection dataProvider() { + @Override + public Collection dataProvider() { final List testData = new ArrayList<>(); testData.add(new Object[]{WeatherType.SUNNY, "The sun hurts the orcs' eyes."}); testData.add(new Object[]{WeatherType.RAINY, "The orcs are dripping wet."}); 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/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTower.java b/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTower.java index 68f190d46..fb88c68d5 100644 --- a/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTower.java +++ b/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTower.java @@ -1,24 +1,20 @@ /** - * The MIT License - * Copyright (c) 2014-2016 Ilkka Seppälä + * 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 + * 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 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. + * 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.singleton; @@ -34,8 +30,10 @@ public final class ThreadSafeLazyLoadedIvoryTower { private static ThreadSafeLazyLoadedIvoryTower instance; private ThreadSafeLazyLoadedIvoryTower() { - // to prevent instantiating by Reflection call - if (instance != null) { + // protect against instantiation via reflection + if (instance == null) { + instance = this; + } else { throw new IllegalStateException("Already initialized."); } } @@ -44,7 +42,6 @@ public final class ThreadSafeLazyLoadedIvoryTower { * The instance gets created only when it is called for first time. Lazy-loading */ public static synchronized ThreadSafeLazyLoadedIvoryTower getInstance() { - if (instance == null) { instance = new ThreadSafeLazyLoadedIvoryTower(); } diff --git a/strategy/README.md b/strategy/README.md index f07397f67..4c7147bed 100644 --- a/strategy/README.md +++ b/strategy/README.md @@ -28,6 +28,9 @@ Use the Strategy pattern when * an algorithm uses data that clients shouldn't know about. Use the Strategy pattern to avoid exposing complex, algorithm-specific data structures * a class defines many behaviors, and these appear as multiple conditional statements in its operations. Instead of many conditionals, move related conditional branches into their own Strategy class +## Tutorial +* [Strategy Pattern Tutorial](https://www.journaldev.com/1754/strategy-design-pattern-in-java-example-tutorial) + ## Credits * [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/template-method/README.md b/template-method/README.md index ad972f06b..5a1402259 100644 --- a/template-method/README.md +++ b/template-method/README.md @@ -24,6 +24,9 @@ The Template Method pattern should be used * when common behavior among subclasses should be factored and localized in a common class to avoid code duplication. This is good example of "refactoring to generalize" as described by Opdyke and Johnson. You first identify the differences in the existing code and then separate the differences into new operations. Finally, you replace the differing code with a template method that calls one of these new operations * to control subclasses extensions. You can define a template method that calls "hook" operations at specific points, thereby permitting extensions only at those points +## Tutorial +* [Template-method Pattern Tutorial](https://www.journaldev.com/1763/template-method-design-pattern-in-java) + ## Credits * [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) 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