001    package counter;
002    
003    import logic.*;
004    
005    public class CounterFactory implements ICounterFactory {
006      
007      public static final CounterFactory Singleton = new CounterFactory();
008      private CounterFactory() {}
009      
010      private static abstract class ACounterState {
011        abstract ICounter decrement();    
012        abstract ICounter increment();
013        abstract Object execute(ICounterAlgo algo, Object... param);
014      }
015      
016      
017      public ICounter makeCounter(final int aCount) {
018        return new ICounter() {
019          private IBooleanAlgo setCountAlgo = new IBooleanAlgo() {
020            public Object trueCase(IBoolean host, Object... param) {
021              counterState = zeroState; 
022              return null;
023            }
024            public Object falseCase(IBoolean host, Object... param) {
025              counterState = nonZeroState;
026              return null;
027            }
028          };
029                
030          private ICounter thisCounter = this; // hack to get self-reference
031          
032          private ACounterState zeroState = new ACounterState() {
033            ICounter decrement() {
034              count = -1;
035              counterState = nonZeroState;
036              return thisCounter;
037            }
038            
039            ICounter increment(){
040              count = 1;
041              counterState = nonZeroState;
042              return thisCounter;
043            }
044            
045            Object execute(ICounterAlgo algo, Object... param) {
046              return algo.zeroCase(thisCounter,param);
047            }
048          };
049          
050          private ACounterState nonZeroState = new ACounterState() {
051            ICounter decrement() {
052              return setCount(--count);
053            }
054            
055            ICounter increment(){
056              count++;
057              return thisCounter;
058            }
059            
060            Object execute(ICounterAlgo algo, Object... param) {
061              return algo.nonZeroCase(thisCounter,param);
062            }
063          };  
064          
065          private int count = aCount;
066          private ACounterState counterState = zeroState;
067          
068          /**
069           * Initializer block
070           * Must come after the fields are initialized so to avoid null ptr errors.
071           */
072          {
073            setCount(aCount); // initialize the counter
074          }
075    
076          
077          public ICounter decrement() {
078            return counterState.decrement();
079          }
080          
081          public ICounter increment() {
082            return counterState.increment();
083          }
084          
085          public int getCount() {
086            return count;
087          }
088          
089          public ICounter setCount(int newCount) { 
090            count = newCount;
091            BooleanFactory.Singleton.makeBoolean(0==count).execute(setCountAlgo);
092            return this;
093          }
094          
095          public Object execute(ICounterAlgo algo, Object... param) {
096            return counterState.execute(algo, param);
097          }
098          
099        };    
100      }
101    }