Merge branch 'master' of github.com:iluwatar/java-design-patterns
This commit is contained in:
commit
3894a0bb6c
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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 <E> Type of Expression
|
||||
* @author Jeroen Meulemeester
|
||||
*/
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
public abstract class ExpressionTest<E extends Expression> {
|
||||
|
||||
/**
|
||||
@ -88,6 +90,13 @@ public abstract class ExpressionTest<E extends Expression> {
|
||||
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()}
|
||||
*/
|
||||
|
@ -38,7 +38,8 @@ public class MinusExpressionTest extends ExpressionTest<MinusExpression> {
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,8 @@ public class MultiplyExpressionTest extends ExpressionTest<MultiplyExpression> {
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,8 @@ public class NumberExpressionTest extends ExpressionTest<NumberExpression> {
|
||||
*
|
||||
* @return The list of parameters used during this test
|
||||
*/
|
||||
public static Stream<Arguments> expressionProvider() {
|
||||
@Override
|
||||
public Stream<Arguments> expressionProvider() {
|
||||
return prepareParameters((f, s) -> f);
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,8 @@ public class PlusExpressionTest extends ExpressionTest<PlusExpression> {
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -33,7 +33,8 @@ import java.util.List;
|
||||
*/
|
||||
public class HobbitsTest extends WeatherObserverTest<Hobbits> {
|
||||
|
||||
static Collection<Object[]> dataProvider() {
|
||||
@Override
|
||||
public Collection<Object[]> dataProvider() {
|
||||
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.RAINY, "The hobbits look for cover from the rain."});
|
||||
|
@ -33,7 +33,8 @@ import java.util.List;
|
||||
*/
|
||||
public class OrcsTest extends WeatherObserverTest<Orcs> {
|
||||
|
||||
static Collection<Object[]> dataProvider() {
|
||||
@Override
|
||||
public Collection<Object[]> dataProvider() {
|
||||
final List<Object[]> 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."});
|
||||
|
@ -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 <O> Type of WeatherObserver
|
||||
* @author Jeroen Meulemeester
|
||||
*/
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
public abstract class WeatherObserverTest<O extends WeatherObserver> {
|
||||
|
||||
private InMemoryAppender appender;
|
||||
@ -67,6 +71,8 @@ public abstract class WeatherObserverTest<O extends WeatherObserver> {
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
public abstract Collection<Object[]> dataProvider();
|
||||
|
||||
/**
|
||||
* Verify if the weather has the expected influence on the observer
|
||||
*/
|
||||
|
@ -35,7 +35,8 @@ import java.util.List;
|
||||
*/
|
||||
public class GHobbitsTest extends ObserverTest<GHobbits> {
|
||||
|
||||
static Collection<Object[]> dataProvider() {
|
||||
@Override
|
||||
public Collection<Object[]> dataProvider() {
|
||||
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.RAINY, "The hobbits look for cover from the rain."});
|
||||
|
@ -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 <O> Type of Observer
|
||||
* @author Jeroen Meulemeester
|
||||
*/
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
public abstract class ObserverTest<O extends Observer> {
|
||||
|
||||
private InMemoryAppender appender;
|
||||
@ -67,6 +70,8 @@ public abstract class ObserverTest<O extends Observer> {
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
public abstract Collection<Object[]> dataProvider();
|
||||
|
||||
/**
|
||||
* Verify if the weather has the expected influence on the observer
|
||||
*/
|
||||
|
@ -35,7 +35,8 @@ import java.util.List;
|
||||
*/
|
||||
public class OrcsTest extends ObserverTest<GOrcs> {
|
||||
|
||||
static Collection<Object[]> dataProvider() {
|
||||
@Override
|
||||
public Collection<Object[]> dataProvider() {
|
||||
final List<Object[]> 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."});
|
||||
|
2
pom.xml
2
pom.xml
@ -147,13 +147,13 @@
|
||||
<module>event-sourcing</module>
|
||||
<module>data-transfer-object</module>
|
||||
<module>throttling</module>
|
||||
|
||||
<module>unit-of-work</module>
|
||||
<module>partial-response</module>
|
||||
<module>eip-wire-tap</module>
|
||||
<module>eip-splitter</module>
|
||||
<module>eip-aggregator</module>
|
||||
<module>retry</module>
|
||||
<module>trampoline</module>
|
||||
</modules>
|
||||
|
||||
<repositories>
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
2
trampoline/.gitignore
vendored
Normal file
2
trampoline/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/target/
|
||||
.idea/
|
45
trampoline/README.md
Normal file
45
trampoline/README.md
Normal 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
77
trampoline/pom.xml
Normal 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>
|
@ -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();
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user