Search code examples
javadesign-patternsstate-pattern

Incomprehension of State pattern


Without State pattern

public static void main(String[] args) {
    Context c = new Context();
    for (int i = 0; i < 10; i++)
        c.someMethod();
}

static class Context {
    public static final int STATE_A = 0;
    public static final int STATE_B = 1;

    private int state = STATE_A;

    public void someMethod() {
        switch (state) {
        case STATE_A:
            System.out.println("StateA.SomeMethod");
            state = STATE_B;
            break;
        case STATE_B:
            System.out.println("StateB.SomeMethod");
            state = STATE_A;
            break;
        default:
            break;
        }
    }
}

State Pattern

public static void main(String[] args) {
        Context context = new Context();
        context.setState(new State1());
        for (int i = 0; i < 10; i++)
            context.someMethod();
    }

    static class Context {
        State state;

        void setState(State state) {
            this.state = state;
        }

        void someMethod() {
            state.someMethod();
            if (state instanceof State1) {
                state = new State2();
            } else {
                state = new State1();
            }
        }
    }

    static interface State {
        void someMethod();
    }

    static class State1 implements State {
        @Override
        public void someMethod() {
            System.out.println("StateA.SomeMethod");
        }
    }

    static class State2 implements State {
        @Override
        public void someMethod() {
            System.out.println("StateB.SomeMethod");
        }
    }

In first case we have only one object but in another we create new object every time when we call someMethod() method.

  1. Is this a correct understanding of the pattern?
  2. How can I solve this problem to not create so many objects?
  3. What else do I need to know about this pattern ?

Solution

  • Well you can do better:

    You must not check the instanceof to advance to new state.
    Each state should be able to go to the next as soon as it runs (Sample:Not even tried to compile).

    Example:

    class Context {  
        State state;                  
    
        public Context(){  
             state = STATE1;//Starting state
        }  
    
        void someMethod() { 
                state.someMethod(this);  //Which is it?State1 or state 2???
        }  
    
    }
    
    public interface States {  
        public static final State STATE1 = new State1();  
        public static final State STATE2 = new State2();   
        //more states here
    
    }  
    
    class State1 implements State {
         @Override         
          public void someMethod(Context ctx) {            
          System.out.println("StateA.SomeMethod");  
          ctx.setState(STATE2); //advance to next state        
      }
    }
    
    class State2 implements State {
        @Override         
        public void someMethod(Context ctx) {            
        System.out.println("StateB.SomeMethod");  
        ctx.setState(STATE1); //advance to next state (back to state 1)          
        }
    }