Skip to content

Instantly share code, notes, and snippets.

@reyabreu
Created November 27, 2018 12:11
Show Gist options
  • Save reyabreu/47a514d86a7b8c2fb7305e1849b423ff to your computer and use it in GitHub Desktop.
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.
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