An introduction to the State pattern of Java design patterns

  • 2020-04-01 03:42:23
  • OfStack

Definition of State: different states, different behaviors; In other words, each state has its own behavior.

When to use the state mode

State mode is more commonly used in practice and is suitable for "State switching". Because we often use If elseif or else to switch states, If this switch occurs repeatedly, we have to think about whether we can take State mode.

Not just by state, but by properties. If the attribute of an object, the object's behavior is different, this frequency is higher in the database system, we are often in a data table of the tail, and the meaning of the property attribute fields, identifies record in some special properties, this change in properties (switch) is possible at any time, you may want to use the State.

In practice, the switch-like state switches are numerous, but sometimes not as obvious, depending on your experience and the depth of your understanding of the system.

The point here is that there are some differences between "on/off state" and "general state judgment", and "general state judgment" also has if.. Elseif structure, for example:


if (which==1) state="hello";
 else if (which==2) state="hi";
 else if (which==3) state="bye";

This is a "general state judgment", the difference of state value is determined by which variable, which has nothing to do with state. If changed to:

 if (state.euqals("bye")) state="hello";
 else if (state.euqals("hello")) state="hi";
 else if (state.euqals("hi")) state="bye";

This is "toggle state", which is to switch the state from "hello" to "hi" to "bye"; When you switch to "hello", as if it were a rotary switch, this State change can be used in State mode.


If only one of the above would "hello"--> Hi - > "" Bye, > "" Hello "this direction switch does not necessarily need to use the State mode, because the State mode will create many subclasses, complicated, but if there is another behavior: switch the above direction switch in reverse, or need to switch arbitrarily, you need State.

See the following example:


public class Context{
  private Color state=null;
  public void push(){
    //If the current red state, switch to blue
    if (state==Color.red) state=Color.blue;
    //If the current state is blue, switch to green
    else if (state==Color.blue) state=Color.green;
    //If the current black state is switched to red
    else if (state==Color.black) state=Color.red;
    //If the current green state is switched to black
    else if (state==Color.green) state=Color.black;
    Sample sample=new Sample(state);
    sample.operate();
  }
  public void pull(){
    //This is the opposite of a push state switch
    if (state==Color.green) state=Color.blue;
    else if (state==Color.black) state=Color.green;
    else if (state==Color.blue) state=Color.red;
    else if (state==Color.red) state=Color.black;
    Sample2 sample2=new Sample2(state);
    sample2.operate();
  }
}

In the above example, we had two actions, push and pull, and those two on-off actions, changed the Context color, so now we need to optimize it using the State mode.

In addition, note: in the above example, the change of state is just a simple color assignment. This specific behavior is very simple, and state is suitable for large specific behavior. Therefore, in this case, it is not necessary to use the state mode in actual use.

For example, a bank account often transitions between the Open and Close states.

For example, in the classic TcpConnection, the State of Tcp is divided into three parts: create a listener and close, and it is transformed repeatedly. The specific behavior of creating a listener and close is not a simple sentence or two, so it is suitable for the use of State.

For example: mailbox POP account, there will be four states, start HaveUsername Authorized quit, the corresponding behavior of each State should be relatively large, suitable for the use of State.

For example, selecting different tools in the toolbox can be seen as switching between different tools, which is suitable for using State. For example, in the specific drawing program, users can choose different tools to draw the straight curve of the box, and this State switch can use State.

How to use the state pattern

State requires two types of entities to participate:

1. State manager state manager is a switch. For example, the Context in the above example is actually a state manager.
2. For a parent class implemented by an abstract class or interface, different states are different subclasses of this parent class.

So, in the Context example above, we're going to modify it to create two types of entities.

The first step is to create a parent class:


public abstract class State{
  public abstract void handlepush(Context c);
  public abstract void handlepull(Context c);
  public abstract void getcolor();
}

The method in the superclass should correspond to the switch behavior in the state manager, in which case, there are two switch actions, push and pull, in the Context. You also need a method getcolor() to get the push or pull results.

Here is the implementation of concrete subclasses:


public class BlueState extends State{
 public void handlepush(Context c){
  //According to the push method "switch to green if blue"; < br / >   c.setState(new GreenState());
 }
 public void handlepull(Context c){
   //According to the pull method "switch to red if blue"; < br / >   c.setState(new RedState());
 }
 public abstract void getcolor(){ return (Color.blue)}
}

Again, subclass implementations of other states are like blue.

The second step is to rewrite the State manager, which is the Context of this example:


ublic class Context{
 private Sate state=null; //I'm going to change Color state to new state state; < br / >  //SetState is used to change the state of the state using setState to achieve the state switch
 pulic void setState(State state){
    this.state=state;
 }
 public void push(){
  //The details of the state switch, in this case a color change, are encapsulated in a subclass of handlepush, where
is not a concern   state.handlepush(this);
  //Because sample is using a switch result in state, use getColor()
  Sample sample=new Sample(state.getColor());
  sample.operate();
 }
 public void pull(){
  state.handlepull(this);
  Sample2 sample2=new Sample2(state.getColor());
  sample2.operate();
 }
}

At this point, we also implement the refactorying process of State.

This is a fairly simple example, and in practice, the handling of handlepush or handelpull is complex.


Related articles: