Merge branch 'master' of github.com:iluwatar/java-design-patterns

This commit is contained in:
Dheeraj Mummareddy 2018-03-04 17:33:58 -05:00
commit 3894a0bb6c
25 changed files with 360 additions and 29 deletions

View File

@ -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. * 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 ## Presentations
* [Abstract Factory Pattern](etc/presentation.html) * [Abstract Factory Pattern](etc/presentation.html)
## Real world examples ## Real world examples
* [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html) * [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html)

View File

@ -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 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. * 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 ## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) * [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)

View File

@ -116,6 +116,9 @@ Use Decorator
* For responsibilities that can be withdrawn * 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 * 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 ## 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.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) [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)

View File

@ -23,6 +23,7 @@
package com.iluwatar.interpreter; package com.iluwatar.interpreter;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
@ -43,6 +44,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
* @param <E> Type of Expression * @param <E> Type of Expression
* @author Jeroen Meulemeester * @author Jeroen Meulemeester
*/ */
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public abstract class ExpressionTest<E extends Expression> { public abstract class ExpressionTest<E extends Expression> {
/** /**
@ -88,6 +90,13 @@ public abstract class ExpressionTest<E extends Expression> {
this.factory = factory; 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<Arguments> expressionProvider();
/** /**
* Verify if the expression calculates the correct result when calling {@link E#interpret()} * Verify if the expression calculates the correct result when calling {@link E#interpret()}
*/ */

View File

@ -38,7 +38,8 @@ public class MinusExpressionTest extends ExpressionTest<MinusExpression> {
* *
* @return The list of parameters used during this test * @return The list of parameters used during this test
*/ */
public static Stream<Arguments> expressionProvider() { @Override
public Stream<Arguments> expressionProvider() {
return prepareParameters((f, s) -> f - s); return prepareParameters((f, s) -> f - s);
} }

View File

@ -38,7 +38,8 @@ public class MultiplyExpressionTest extends ExpressionTest<MultiplyExpression> {
* *
* @return The list of parameters used during this test * @return The list of parameters used during this test
*/ */
public static Stream<Arguments> expressionProvider() { @Override
public Stream<Arguments> expressionProvider() {
return prepareParameters((f, s) -> f * s); return prepareParameters((f, s) -> f * s);
} }

View File

@ -42,7 +42,8 @@ public class NumberExpressionTest extends ExpressionTest<NumberExpression> {
* *
* @return The list of parameters used during this test * @return The list of parameters used during this test
*/ */
public static Stream<Arguments> expressionProvider() { @Override
public Stream<Arguments> expressionProvider() {
return prepareParameters((f, s) -> f); return prepareParameters((f, s) -> f);
} }

View File

@ -38,7 +38,8 @@ public class PlusExpressionTest extends ExpressionTest<PlusExpression> {
* *
* @return The list of parameters used during this test * @return The list of parameters used during this test
*/ */
public static Stream<Arguments> expressionProvider() { @Override
public Stream<Arguments> expressionProvider() {
return prepareParameters((f, s) -> f + s); return prepareParameters((f, s) -> f + s);
} }

View File

@ -28,7 +28,7 @@ package com.iluwatar.objectmother;
public final class RoyaltyObjectMother { 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. * @return An instance of {@link com.iluwatar.objectmother.King} with the standard properties.
*/ */
public static King createSoberUnhappyKing() { public static King createSoberUnhappyKing() {

View File

@ -33,7 +33,8 @@ import java.util.List;
*/ */
public class HobbitsTest extends WeatherObserverTest<Hobbits> { public class HobbitsTest extends WeatherObserverTest<Hobbits> {
static Collection<Object[]> dataProvider() { @Override
public Collection<Object[]> dataProvider() {
final List<Object[]> testData = new ArrayList<>(); final List<Object[]> testData = new ArrayList<>();
testData.add(new Object[]{WeatherType.SUNNY, "The happy hobbits bade in the warm sun."}); 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."}); testData.add(new Object[]{WeatherType.RAINY, "The hobbits look for cover from the rain."});

View File

@ -33,7 +33,8 @@ import java.util.List;
*/ */
public class OrcsTest extends WeatherObserverTest<Orcs> { public class OrcsTest extends WeatherObserverTest<Orcs> {
static Collection<Object[]> dataProvider() { @Override
public Collection<Object[]> dataProvider() {
final List<Object[]> testData = new ArrayList<>(); final List<Object[]> testData = new ArrayList<>();
testData.add(new Object[]{WeatherType.SUNNY, "The sun hurts the orcs' eyes."}); testData.add(new Object[]{WeatherType.SUNNY, "The sun hurts the orcs' eyes."});
testData.add(new Object[]{WeatherType.RAINY, "The orcs are dripping wet."}); testData.add(new Object[]{WeatherType.RAINY, "The orcs are dripping wet."});

View File

@ -23,11 +23,14 @@
package com.iluwatar.observer; package com.iluwatar.observer;
import com.iluwatar.observer.utils.InMemoryAppender; import com.iluwatar.observer.utils.InMemoryAppender;
import java.util.Collection;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
@ -39,6 +42,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
* @param <O> Type of WeatherObserver * @param <O> Type of WeatherObserver
* @author Jeroen Meulemeester * @author Jeroen Meulemeester
*/ */
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public abstract class WeatherObserverTest<O extends WeatherObserver> { public abstract class WeatherObserverTest<O extends WeatherObserver> {
private InMemoryAppender appender; private InMemoryAppender appender;
@ -67,6 +71,8 @@ public abstract class WeatherObserverTest<O extends WeatherObserver> {
this.factory = factory; this.factory = factory;
} }
public abstract Collection<Object[]> dataProvider();
/** /**
* Verify if the weather has the expected influence on the observer * Verify if the weather has the expected influence on the observer
*/ */

View File

@ -35,7 +35,8 @@ import java.util.List;
*/ */
public class GHobbitsTest extends ObserverTest<GHobbits> { public class GHobbitsTest extends ObserverTest<GHobbits> {
static Collection<Object[]> dataProvider() { @Override
public Collection<Object[]> dataProvider() {
final List<Object[]> testData = new ArrayList<>(); final List<Object[]> testData = new ArrayList<>();
testData.add(new Object[]{WeatherType.SUNNY, "The happy hobbits bade in the warm sun."}); 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."}); testData.add(new Object[]{WeatherType.RAINY, "The hobbits look for cover from the rain."});

View File

@ -26,9 +26,11 @@ import com.iluwatar.observer.WeatherType;
import com.iluwatar.observer.utils.InMemoryAppender; import com.iluwatar.observer.utils.InMemoryAppender;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import java.util.Collection;
import java.util.function.Supplier; import java.util.function.Supplier;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -39,6 +41,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
* @param <O> Type of Observer * @param <O> Type of Observer
* @author Jeroen Meulemeester * @author Jeroen Meulemeester
*/ */
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public abstract class ObserverTest<O extends Observer> { public abstract class ObserverTest<O extends Observer> {
private InMemoryAppender appender; private InMemoryAppender appender;
@ -67,6 +70,8 @@ public abstract class ObserverTest<O extends Observer> {
this.factory = factory; this.factory = factory;
} }
public abstract Collection<Object[]> dataProvider();
/** /**
* Verify if the weather has the expected influence on the observer * Verify if the weather has the expected influence on the observer
*/ */

View File

@ -35,7 +35,8 @@ import java.util.List;
*/ */
public class OrcsTest extends ObserverTest<GOrcs> { public class OrcsTest extends ObserverTest<GOrcs> {
static Collection<Object[]> dataProvider() { @Override
public Collection<Object[]> dataProvider() {
final List<Object[]> testData = new ArrayList<>(); final List<Object[]> testData = new ArrayList<>();
testData.add(new Object[]{WeatherType.SUNNY, "The sun hurts the orcs' eyes."}); testData.add(new Object[]{WeatherType.SUNNY, "The sun hurts the orcs' eyes."});
testData.add(new Object[]{WeatherType.RAINY, "The orcs are dripping wet."}); testData.add(new Object[]{WeatherType.RAINY, "The orcs are dripping wet."});

View File

@ -147,13 +147,13 @@
<module>event-sourcing</module> <module>event-sourcing</module>
<module>data-transfer-object</module> <module>data-transfer-object</module>
<module>throttling</module> <module>throttling</module>
<module>unit-of-work</module> <module>unit-of-work</module>
<module>partial-response</module> <module>partial-response</module>
<module>eip-wire-tap</module> <module>eip-wire-tap</module>
<module>eip-splitter</module> <module>eip-splitter</module>
<module>eip-aggregator</module> <module>eip-aggregator</module>
<module>retry</module> <module>retry</module>
<module>trampoline</module>
</modules> </modules>
<repositories> <repositories>

View File

@ -1,24 +1,20 @@
/** /**
* The MIT License * The MIT License Copyright (c) 2014-2016 Ilkka Seppälä
* Copyright (c) 2014-2016 Ilkka Seppälä
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* of this software and associated documentation files (the "Software"), to deal * associated documentation files (the "Software"), to deal in the Software without restriction,
* in the Software without restriction, including without limitation the rights * including without limitation the rights to use, copy, modify, merge, publish, distribute,
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * The above copyright notice and this permission notice shall be included in all copies or
* all copies or substantial portions of the Software. * substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* 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.
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/ */
package com.iluwatar.singleton; package com.iluwatar.singleton;
@ -34,8 +30,10 @@ public final class ThreadSafeLazyLoadedIvoryTower {
private static ThreadSafeLazyLoadedIvoryTower instance; private static ThreadSafeLazyLoadedIvoryTower instance;
private ThreadSafeLazyLoadedIvoryTower() { private ThreadSafeLazyLoadedIvoryTower() {
// to prevent instantiating by Reflection call // protect against instantiation via reflection
if (instance != null) { if (instance == null) {
instance = this;
} else {
throw new IllegalStateException("Already initialized."); 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 * The instance gets created only when it is called for first time. Lazy-loading
*/ */
public static synchronized ThreadSafeLazyLoadedIvoryTower getInstance() { public static synchronized ThreadSafeLazyLoadedIvoryTower getInstance() {
if (instance == null) { if (instance == null) {
instance = new ThreadSafeLazyLoadedIvoryTower(); instance = new ThreadSafeLazyLoadedIvoryTower();
} }

View File

@ -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 * 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 * 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 ## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) * [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)

View File

@ -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 * 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 * 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 ## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) * [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)

2
trampoline/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target/
.idea/

45
trampoline/README.md Normal file
View File

@ -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)

77
trampoline/pom.xml Normal file
View File

@ -0,0 +1,77 @@
<?xml version="1.0"?>
<!--
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.
-->
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.iluwatar</groupId>
<artifactId>java-design-patterns</artifactId>
<version>1.19.0-SNAPSHOT</version>
</parent>
<artifactId>trampoline</artifactId>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<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>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19</version>
<configuration>
<skipTests>false</skipTests>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,85 @@
package com.iluwatar.trampoline;
import java.util.stream.Stream;
/**
* <p>Trampoline pattern allows to define recursive algorithms by iterative loop </p>
* <p>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)}.</p>
* <p>Essential we convert looping via recursion into iteration,
* the key enabling mechanism is the fact that {@link #more(Trampoline)} is a lazy operation.</p>
*
* @param <T> is type for returning result.
*/
public interface Trampoline<T> {
T get();
/**
* @return next stage
*/
default Trampoline<T> 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 <T> Trampoline<T> 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 <T> Trampoline<T> more(final Trampoline<Trampoline<T>> trampoline) {
return new Trampoline<T>() {
@Override
public boolean complete() {
return false;
}
@Override
public Trampoline<T> jump() {
return trampoline.result();
}
@Override
public T get() {
return trampoline(this);
}
T trampoline(final Trampoline<T> trampoline) {
return Stream.iterate(trampoline, Trampoline::jump)
.filter(Trampoline::complete)
.findFirst()
.get()
.result();
}
};
}
}

View File

@ -0,0 +1,58 @@
/**
* The MIT License
* Copyright (c) 2014-2016 Ilkka Seppälä
* <p>
* 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:
* <p>
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* <p>
* 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;
/**
* <p>Trampoline pattern allows to define recursive algorithms by iterative loop </p>
* <p>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.</p>
*/
@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<Integer> loop(int times, int prod) {
if (times == 0) {
return Trampoline.done(prod);
} else {
return Trampoline.more(() -> loop(times - 1, prod * times));
}
}
}

View File

@ -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);
}
}