0

Background

I have a command that uses the state pattern. When the command state changes I am notified in the UI that for example class stageOneState is now the active state. Is it bad practice to check the state class type using a string as an identifier? Is this undoing the work of the state pattern?

What would be an alternative?

Example

if (notifiedState.type == "state1") {
// Update UI accroding to state1
} else ...

Example

Example from http://www.tutorialspoint.com/design_pattern/state_pattern.htm

public interface State {
   public void doAction(Context context);
}

public class StartState implements State {

   public void doAction(Context context) {
      System.out.println("Player is in start state");
      context.setState(this);   
   }

   public String toString(){
      return "Start State";
   }
}

public class StopState implements State {

   public void doAction(Context context) {
      System.out.println("Player is in stop state");
      context.setState(this);   
   }

   public String toString(){
      return "Stop State";
   }
}

public class Context {
   private State state;

   public Context(){
      state = null;
   }

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

   public State getState(){
      return state;
   }
}

public class StatePatternDemo {
   public static void main(String[] args) {
      Context context = new Context();

      StartState startState = new StartState();
      startState.doAction(context);

      System.out.println(context.getState().toString());

      StopState stopState = new StopState();
      stopState.doAction(context);

      System.out.println(context.getState().toString());
   }
}
jaco0646
  • 15,303
  • 7
  • 59
  • 83
  • 2
    Even if this was just an example, please mind this question: [How do I compare strings in Java?](http://stackoverflow.com/q/513832) – Tom Jun 06 '15 at 11:06
  • @tom In this case it's not an error to compare strings using `==`. OP's code would actually work as expected (due to string *interning*). – Bohemian Jun 06 '15 at 15:08
  • @Bohemian Not necessarily, because we don't know he would set the state to `notifiedState.type`. If he bypasses the String interning by generating a new String (e.g. String concatenation `"state" + stateId`, `substring` or whatever) his comparison would fail. And he would get problems if he likes to persist objects in their current state, because the deserialized or read objects (e.g. JSON file) also wouldn't profit from String interning. I know what you mean, but in my opinion String comparison with `==` is too error-prone (especially for starters) so I can't keep that unmentioned :D. – Tom Jun 06 '15 at 15:49

2 Answers2

1
  1. You undo the state pattern when you check the state of an object from the outside and then act differently depending on which state it is. If it seems more convenient, then probably state is the wrong tool for the job.

  2. The sentence "command having a state" raises a red flag. Is this some ungodly mashup of state and command patterns?

  3. There is a terrible error in the example: you are comparing strings using identity instead of value.

  4. Generally, if you have any doubts about any pattern, just don't try to use it. They are poisonous animals, better studied from safe distance.

fdreger
  • 12,264
  • 1
  • 36
  • 42
  • In this case it's not an error to compare strings using `==`. OP's code would actually work as expected (due to string *interning*). – Bohemian Jun 06 '15 at 15:06
  • @Bohemian. Please, don't nitpick, especially when you are wrong. You have no idea where type string mentioned in the example comes from - maybe it comes from a configuration file? maybe the whole object was serialized? The comparison _is_ an error. – fdreger Jun 07 '15 at 13:07
0

This pattern is sometimes called stringly typed (a pun on strongly typed).

The best approach is to use an enum.

Bohemian
  • 412,405
  • 93
  • 575
  • 722