Created
November 27, 2018 12:11
-
-
Save reyabreu/47a514d86a7b8c2fb7305e1849b423ff to your computer and use it in GitHub Desktop.
Implemented a Fibonacci sequence generator using a state machine design pattern - just to highlight how individual states should manage their own logic and transitions and not depend on an external controlling context.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.jetbrains.annotations.NotNull; | |
import org.junit.Test; | |
import org.junit.runner.RunWith; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.context.annotation.Bean; | |
import org.springframework.context.annotation.Configuration; | |
import org.springframework.test.context.ContextConfiguration; | |
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; | |
import java.util.Iterator; | |
import java.util.NoSuchElementException; | |
import java.util.stream.Collectors; | |
import java.util.stream.StreamSupport; | |
@RunWith(SpringJUnit4ClassRunner.class) | |
@ContextConfiguration | |
public class TestFibonacciStateMachine { | |
private final Logger logger = LoggerFactory.getLogger(this.getClass()); | |
@Autowired | |
private Fibonacci fibonacci; | |
@Test | |
public void hasNext_hasMoreItems_true() { | |
final String collected = StreamSupport.stream(fibonacci.spliterator(), false) | |
.map(String::valueOf) | |
.collect(Collectors.joining(", ")); | |
logger.info("{}", collected); | |
} | |
interface FiboState { | |
void next(FibonacciGenerator fibonacciGenerator); | |
long getCurrentValue(); | |
boolean hasNextValue(); | |
class ZeroState implements FiboState { | |
private final int numberCount; | |
public ZeroState(int numberCount) { | |
this.numberCount = numberCount; | |
} | |
@Override | |
public void next(FibonacciGenerator fibonacciGenerator) { | |
fibonacciGenerator.setNextState(new RunningState(numberCount)); | |
} | |
@Override | |
public long getCurrentValue() { | |
return 1; | |
} | |
@Override | |
public boolean hasNextValue() { | |
return true; | |
} | |
} | |
class RunningState implements FiboState { | |
private final int numberCount; | |
private int count = 1; | |
private long minusOneValue = 1; | |
private long minusTwoValue = 0; | |
public RunningState(int numberCount) { | |
this.numberCount = numberCount; | |
} | |
@Override | |
public void next(FibonacciGenerator fibonacciGenerator) { | |
if (count >= numberCount) { | |
fibonacciGenerator.setNextState(new HaltedState()); | |
} | |
} | |
@Override | |
public long getCurrentValue() { | |
final long result = minusOneValue + minusTwoValue; | |
minusTwoValue = minusOneValue; | |
minusOneValue = result; | |
count++; | |
return result; | |
} | |
@Override | |
public boolean hasNextValue() { | |
return true; | |
} | |
} | |
class HaltedState implements FiboState { | |
@Override | |
public void next(FibonacciGenerator fibonacciGenerator) { | |
} | |
@Override | |
public long getCurrentValue() { | |
throw new NoSuchElementException(); | |
} | |
@Override | |
public boolean hasNextValue() { | |
return false; | |
} | |
} | |
} | |
@Configuration | |
static class TestConfig { | |
@Bean | |
public Fibonacci fibonacci() { | |
return new Fibonacci(20); | |
} | |
} | |
static class FibonacciGenerator implements Iterator<Long> { | |
private FiboState state; | |
public FibonacciGenerator(int numberCount) { | |
state = new FiboState.ZeroState(numberCount); | |
} | |
public void nextState() { | |
state.next(this); | |
} | |
@Override | |
public Long next() { | |
final long result = state.getCurrentValue(); | |
nextState(); | |
return result; | |
} | |
@Override | |
public boolean hasNext() { | |
return state.hasNextValue(); | |
} | |
public void setNextState(FiboState nextState) { | |
this.state = nextState; | |
} | |
} | |
static class Fibonacci implements Iterable<Long> { | |
private final int numberCount; | |
public Fibonacci(int numberCount) { | |
this.numberCount = numberCount; | |
} | |
@NotNull | |
@Override | |
public Iterator<Long> iterator() { | |
return new FibonacciGenerator(numberCount); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment