This is the fifth day of my participation in the August More text Challenge. For details, see:August is more challenging

What is State mode?

concept

State patterns belong to behavioral patterns, which define that the behavior of an object is determined by its internal State.

If you want to learn about state patterns, you have to talk about state machines. What is a state machine? A state machine is a list of states of something, a study of the switching behavior of those states, and then a map of the state that can be connected.

Here is the gate, for example, in Guangzhou subway, after we pass the security check, if we want to enter the subway, we need to swipe the card to go through the gate, here the gate has many states, before the card is closed, we can not pass the gate; After swiping the card, there will be an intermediate state: processing state. In this state, we have swiped the card, but the machine is still processing it. We can’t pass without opening the door. When it’s done, it’s turned on, we can pass it, and then it’s turned off. In this process, the gate has three states: closed, processing, and open. We need to interact with the gate: swipe, pass. Let me draw a state diagram below:

As I learned, the implementation of this state pattern is almost exactly the same as the strategy pattern.

The state pattern is a derivative of the strategy pattern, although the implementation is identical, but the problem is different. The strategy mode is to encapsulate the algorithms so that they can be replaced with each other to improve the reusability of the code. The state mode is all about the state machine, providing an implementation of the state machine. State mode reduces the use of if-else and switch to determine the current state, which will be demonstrated later.

advantages

  1. State objects encapsulate state transition rules, reducing the use of judgment statements.
  2. Different environment objects can share state objects, reducing the number of objects.
  3. Consistent with the single responsibility principle. Separating out the different states and behaviors makes the responsibility of each state class clearer and helps the system expand.

disadvantages

  1. The open and closed principle was not observed. If a new state is added and you want to use it, add the logic to transition to the new state to the old state class.
  2. Design and implementation are complex.

The principle of

“+” means compliance, and “-” means noncompliance or irrelevant

The principle of Open the closed Single responsibility Di milt Replacement on the Richter scale Dependency inversion Interface segregation Synthesis of reuse
+ +

Applicable scenario

  1. When an object’s behavior depends on its state.
  2. Situations that require a large number of judgments or branch statements.

How to implement

To implement the state pattern, you need three things:

  1. Abstract Context: It needs to define methods to interact with the user and have a state object to which all methods are delegated for implementation
  2. Context class: Implements the Context abstract class and extends other functionality.
  3. State interface/abstract class: Defines the behavior of the State, which is consistent with the behavior of the environment class, and also needs to implement the logic of State switching.
  4. Concrete State class: Implement abstract State interface/abstract class to realize State transition logic.

The class diagram

example

As an example of the previous gate, there are three states of the gate: closed, in process, and open, and the behaviors that interact with the gate: swipe and pass.

Examples that do not use state modes

Here’s a quick look at what the implementation would look like without state mode:

** @author xuxiaobai */ public class NoUserStatePatternGate {/** * Created on 2021/6/15. ** @author xuxiaobai */ public class NoUserStatePatternGate {// current status, Private String currentState=CLOSE_STATE; Private static String CLOSE_STATE="closed"; Private static String OPEN_STATE="open"; Private static String PROCESSING=" PROCESSING "; Public void pay(){if (this.currentstate.equals (CLOSE_STATE)){system.out.println (" CLOSE_STATE "); Being dealt with "); This. currentState=PROCESSING; Random random=new Random(); If (random.nextBoolean()){processSuccess(); }else { processFail(); } return; } if (this.currentstate.equals (PROCESSING)){system.out.println (" please wait. Being dealt with "); return; } if (this.currentstate.equals (OPEN_STATE)){system.out.println (" The lock is open, please pass "); return; } /** * pass */ public void pass(){if (this.currentstate.equals (CLOSE_STATE)){system.out.println (" CLOSE_STATE "); return; } if (this.currentstate.equals (PROCESSING)){system.out.println (" please wait. Being dealt with "); return; } if (this.currentstate. Equals (OPEN_STATE)){system.out.println (" pass, lock "); this.currentState=CLOSE_STATE; return; }} /** * processFail */ private void processFail(){system.out.println (" processFail! "); ); CurrentState =CLOSE_STATE; this.currentState=CLOSE_STATE; } /** * processSuccess */ private void processSuccess(){system.out.println (" processSuccess! ") ); CurrentState =OPEN_STATE; currentState=OPEN_STATE; }}Copy the code

Testing:

** @author xuxiaobai */ public class StateTest {public static void main(String[]); args) { NoUserStatePatternGate gate=new NoUserStatePatternGate(); gate.pass(); gate.pay(); gate.pay(); gate.pass(); gate.pay(); gate.pass(); gate.pay(); gate.pass(); gate.pay(); gate.pass(); /** * Result: * cannot pass, please swipe card * swipe card successfully, processing * processing successfully! * The gate has been opened, please pass * passed, the gate is closed * Swipe card success, processing * processing success! * Passed, gate closed * swipe card successful, processing * processing failed! * Cannot pass, please swipe card * swipe successful, processing * processing failed! * Cannot pass, please swipe your card */}}Copy the code

The basic function is implemented, minus the operation of payment and deduction, if you want to implement, you can copy down to supplement.

There are a lot of if-else here, it’s better to change it to switch, but it still makes the whole code very cumbersome, and if you want to add more states in the future, you have to add if-else, and the logic is very confusing, and if you add a few more states, you may not be able to control the ordinary people, Let’s look at how this is implemented using the state pattern.

Use state mode

The code is a little bit more complicated by adding a shared state object, and the other thing is to get rid of all the if-else operations that determine the current state, so that every logical operation of the if-else is spread out into the state class.

The class diagram

The class diagram is a bit messy, but the state pattern is a bit complicated to implement, but the responsibilities of each class are clear, as seen in the following code.

The environment class

Environment abstract class

** @author xuxiaobai */ Created on 2021/6/15. ** @author Xuxiaobai */ Public Abstract class AbstractGate {/** * */ protected AbstractGateState state; Public void pay() {this.state.pay(this); } /** * pass */ public void pass() {this.state.pass(this); } public AbstractGateState getState() { return state; } protected AbstractGate setState(AbstractGateState state) { this.state = state; return this; }}Copy the code

Specific environment

** @author xuxiaobai */ Public class SubwayGate extends AbstractGate{public SubwayGate(){// this(false) is turned off by default; } public SubwayGate(Boolean isOpen){// enable Class stateClass; if (isOpen){ stateClass= OpenState.class; }else { stateClass=ClosedState.class; } this.state=AbstractGateState.getState(stateClass); }}Copy the code
State class

State abstract class

** @author Xuxiaobai */ public Abstract class AbstractGateState {private static Map<Class,AbstractGateState> stateMap=new HashMap<>(); Public abstract void pay(AbstractGate gate); Public abstract void pass(AbstractGate gate); /** * The environment class only interacts with the user by doing two actions: /** * the environment class only interacts with the user by doing two actions: Pay, pass, Throws IllegalAccessException */ Public void Handle (AbstractGate Gate) throws IllegalAccessException  { throw new IllegalAccessException(); } /** * use this method to get the state object, * @param stateClass * @return */ protected static final AbstractGateState getState(Class stateClass){ AbstractGateState state = stateMap.get(stateClass); If (state==null){synchronized (abstractgatestat.class){state= statemap.get (stateClass); if (state==null){ try { state= (AbstractGateState) stateClass.newInstance(); stateMap.put(stateClass,state); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } } } return state; }}Copy the code

The closed position

** @author Xuxiaobai */ public Class ClosedState extends AbstractGateState { @override public void pay(AbstractGate Gate) {// System.out.println(" Override public void pay(AbstractGate gate) "); AbstractGateState processingState = getState(processingState.class); gate.setState(processingState); try { processingState.handle(gate); } catch (IllegalAccessException e) {}} @override public void pass(AbstractGate Gate) {system.out.println (" failed to pass, failed to pass, failed to pass ") Please swipe "); }}Copy the code

In-process state

** @author Xuxiaobai */ Public Class ProcessingState extends Private Random Random = new Random(); AbstractGateState {// simulate failure probability private Random Random = new Random(); @override public void pay(AbstractGate Gate) {system.out.println (); Being dealt with "); return; } @override public void pass(AbstractGate Gate) {system.out.println (" please wait. Being dealt with "); return; } @override public void Handle (AbstractGate Gate) throws IllegalAccessException {if (random.nextBoolean()) { System.out.println(" Processing failed! ); gate.setState(getState(ClosedState.class)); } else {system.out.println (" Processing succeeded! "); ); gate.setState(getState(OpenState.class)); }}}Copy the code

open

** @author Xuxiaobai */ public Class OpenState extends AbstractGateState { @override public void pay(AbstractGate Gate) {system.out.println (" the gate is open, please pass "); return; } @override public void pass(AbstractGate Gate) {system.out.println (" pass, gate closed "); Gate. SetState (getState(closedstate.class)); return; }}Copy the code
test
** @author xuxiaobai */ public class StateTest {public static void main(String[]); args) { AbstractGate gate=new SubwayGate(); gate.pass(); gate.pay(); gate.pay(); gate.pay(); gate.pay(); gate.pass(); gate.pay(); gate.pass(); gate.pay(); gate.pass(); gate.pay(); gate.pass(); /** * Result: * cannot pass, please swipe card * swipe card successfully, processing * processing successfully! * The gate has been opened, please pass * passed, the gate is closed * Swipe card success, processing * processing success! * Passed, gate closed * swipe card successful, processing * processing failed! * Cannot pass, please swipe card * swipe successful, processing * processing failed! * Cannot pass, please swipe your card */}}Copy the code

There’s a probability that this will pass, so it’s going to be different every time.

This is the end of it. You see this, but still don’t give me a like?

conclusion

Although the state pattern is the strategy pattern of derivative, but they will not exist differences in the use, the only need to pay attention to is the logic of thinking is different, both the strategy pattern only focus on the algorithm, logic and so on packaging to a class, and the state pattern is encapsulate algorithms with logic and state into a class, is inseparable from the state of the state model, You can say that the state pattern includes the policy pattern.

— — — — — — — — — — — — — — —

The more you know, the more you don’t know.

If you have questions about this article, please comment directly or send me a personal message. If you think my writing is good, you can also support me by clicking “like”

Without permission, shall not be reproduced!