Pregunta

I use state pattern in my application because my state-entities has API the behaviour of which changes due to current state.

In my case that state-dependent API consists only from one method - changeState. This method change state and also execute some state-dependent logic.

But there is the circumstance that made me to ask this question: State dependent logic depends not only on current state, but also it depends on newState (see code below). So I have to use instanceof.

Question: what is the true way to get rid of instanceof?

public interface IStateEntity {
  void changeState(IState newState);
}

public interface IState {
  void doStateDependentLogic(IState newState);
}

public class StateEntityImpl {

  private IState state;

  @Override
  public void changeState(IState newState) {
    state.doStateDependentLogic(newState);
    state = newState;  
  }
}

public class StateImplA { //each state implementation is a singleton

  @Override
  public void doStateDependentLogic(IState newState) {
      // HARDSHIP #1: state dependent logic depends not only on current state, but also it depends on newState. So I have to use `instanceof`
     if (newState instanceof StateImplA) {
       //do one logic
     } else if (newState instanceof StateImplB) {
       //do another logic
     }
  }
}

EDIT (why not enum):

If enum replace a getClass().getSimpleName(): because it's functional programming paradigm. When I make my architecture in such way that it relies on className, that the first sign that something goes wrong.It seems for me that change instanceof to enum doersn't mean to change architecture, but only to change one bad for worse.

If make each IState implementation as enum: each IState implementation is Hibernate entity.

¿Fue útil?

Solución

The accepted way in Java of creating a singleton is with an enum. This provides thread safe initialisation as well as JVM guaranteed singleton status. There are many ways for creating a second instance of a class that is not an enum.

The additional benefit of using an enum is that you are allowed to case switch on the enum in your logic:

public enum State {

    STATE_A {
        @Override
        public void doStateDependentLogic(final State newState) {
            switch (newState) {
                case STATE_B:
                    //do stuff
                //case SOME_OTHER_STATE
            }
        }
    },
    STATE_B {
        @Override
        public void doStateDependentLogic(final State newState) {
        }
    };

    public abstract void doStateDependentLogic(State newState);
}

I don't know where you got the idea that an enum is a functional programming paradigm. This is not the case. enum in Java is designed to do exactly what you want.

Otros consejos

Your problem is not really the state pattern. Your problem lies after the state pattern has done it's job which is to route a method call to a certain implementation that represents a state.

The instanceof problem with subclasses is an independent problem. The solution here is to avoid instanceof like in other code too, preferably with with interaction between the state and it's next state via methods. switch over enum types looks nicer already but is not much better since you still depend on the concrete type of the other object. Could be considered okay since all of them are defined in the same class so the dependency is just on yourself.

What you should end up with in the best case looks something like

  @Override
  public void doStateDependentLogic(IState newState) {
     if (newState.isBeautiful()) {
         System.out.println(newState.getYourPartOfTheInterAction(this));
     } else {
         somethingElse();
     }
  }

i.e. method calls on abstractions without being concerned about the implementation details.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top