Write in front
- Take notes of learning design patterns
- Improve the flexible use of design patterns
Learning address
https://www.bilibili.com/vide…
https://www.bilibili.com/vide…
Reference articles
http://c.biancheng.net/view/1…
Project source code
https://gitee.com/zhuang-kang/DesignPattern
25. Status mode
25.1 definition and characteristics of state mode
Definition of state mode:For stateful objects, the complex “judgment logic” is extracted into different state objects, allowing the state object to change its behavior when its internal state changes.
State mode is an object behavior mode. Its main advantages are as follows.
- The structure is clear, and the state mode localizes the behavior related to a specific state into one state, and separates the behavior of different states to meet the “single responsibility principle”.
- Display the state transition to reduce the interdependence between objects. Introducing different states into independent objects will make the state transition more explicit and reduce the interdependence between objects.
- The responsibilities of the status class are clear, which is conducive to the expansion of the program. It is easy to add new states and transitions by defining new subclasses.
The main disadvantages of state mode are as follows.
- The use of state mode will inevitably increase the number of classes and objects of the system.
- The structure and implementation of state mode are complex. Improper use will lead to confusion of program structure and code.
- The state mode does not support the opening and closing principle very well. For the state mode that can switch states, adding a new state class requires modifying the source code responsible for state transformation, otherwise it cannot switch to the new state, and modifying the behavior of a state class also requires modifying the source code of the corresponding class.
25.2 structure and implementation of state mode
[example] the state of an elevator is controlled by buttons. An elevator has door opening state, door closing state, stop state and operation state. Each state change may be updated according to other states. For example, if the elevator door is in the running state, the door opening operation cannot be performed, and if the elevator door is in the stopped state, the door opening operation can be performed
public interface ILift {
//4 states of elevator
//Door opening status
public final static int OPENING_STATE = 1;
//Closing state
public final static int CLOSING_STATE = 2;
//Running status
public final static int RUNNING_STATE = 3;
//Stop state
public final static int STOPPING_STATE = 4;
//Set the status of the elevator
public void setState(int state);
//Elevator action
public void open();
public void close();
public void run();
public void stop();
}
public class Lift implements ILift {
private int state;
@Override
public void setState(int state) {
this.state = state;
}
//Execute closing action
@Override
public void close() {
switch (this.state) {
case OPENING_STATE:
System. out. Println ("the elevator is closed...)// The elevator door can be closed only when the door is opened, which can be viewed according to the elevator status table
this. setState(CLOSING_STATE);// After closing the door, the elevator is closed
break;
case CLOSING_STATE:
//Do nothing // the door is closed and cannot be closed
break;
case RUNNING_STATE:
//Do nothing // the elevator door is closed during operation and cannot be closed
break;
case STOPPING_STATE:
//Do nothing // the elevator is also closed when it stops and cannot be closed
break;
}
}
//Execute door opening action
@Override
public void open() {
switch (this.state) {
case OPENING_ State: // the door has been opened. You can't open it again
//do nothing
break;
case CLOSING_STATE://Closing state,门打开:
System. out. Println ("elevator door opened...);
this.setState(OPENING_STATE);
break;
case RUNNING_STATE:
//Do nothing when running, the elevator cannot open the door
break;
case STOPPING_STATE:
System. out. Println ("elevator door opened...)// The elevator has stopped. You can open the door
this.setState(OPENING_STATE);
break;
}
}
//Execute running action
@Override
public void run() {
switch (this.state) {
case OPENING_ State: // the elevator cannot leave the door open
//do nothing
break;
case CLOSING_ State: // the door is closed and can run
System. out. Println ("the elevator is running...);
this. setState(RUNNING_STATE);// It is now running
break;
case RUNNING_STATE:
//Do nothing is already running
break;
case STOPPING_STATE:
System. out. Println ("the elevator is running...);
this.setState(RUNNING_STATE);
break;
}
}
//Execute stop action
@Override
public void stop() {
switch (this.state) {
case OPENING_ State: // the elevator that opens the door has stopped (under normal circumstances)
//do nothing
break;
case CLOSING_ State: // it can only be stopped when the door is closed
System. out. Println ("elevator stopped...);
this.setState(STOPPING_STATE);
break;
case RUNNING_ The state: // runtime can of course be stopped
System. out. Println ("elevator stopped...);
this.setState(STOPPING_STATE);
break;
case STOPPING_STATE:
//do nothing
break;
}
}
}
public class Client {
public static void main(String[] args) {
Lift lift = new Lift();
lift. setState(ILift.STOPPING_STATE);// The elevator stopped
lift. open();// Open the door
lift. close();// close
lift. run();// function
lift. stop();// stop it
}
}
problem analysis
- A lot of judgment like switch… Case is used (the same is true for if… Else), which makes the readability of the program worse.
- Poor scalability. If the power-off status is added, we need to modify the above judgment logic
25.2.1 structure of state mode
- Context role: also known as context, it defines the interface required by the client program, maintains a current state, and delegates the operations related to the state to the current state object for processing.
- Abstract state role: define an interface to encapsulate the behavior corresponding to a specific state in an environment object.
- Concrete state role: implement the behavior corresponding to the abstract state.
25.2.2 code implementation
Relational class diagram
LiftState
package com.zhuang.state.after;
/**
* @Classname LiftState
*@ description abstract state class
* @Date 2021/3/31 10:50
* @Created by dell
*/
public abstract class LiftState {
//Define an environmental role, that is, the function change caused by the change of packaging state
protected Context context;
public void setContext(Context context) {
this.context = context;
}
//Elevator door opening action
public abstract void open();
//Elevator door closing action
public abstract void close();
//Elevator operation
public abstract void run();
//The elevator stops
public abstract void stop();
}
Context
package com.zhuang.state.after;
/**
* @Classname Context
*@ description define the status of all elevator doors
* @Date 2021/3/31 10:53
* @Created by dell
*/
public class Context {
//Define all elevator States
//When the door is open, the elevator can only be closed
public final static OpeningState OPENNING_STATE = new OpeningState();
//In the closed state, the elevator can run, stop and open the door
public final static ClosingState CLOSEING_STATE = new ClosingState();
//Running state, at this time, the elevator can only stop
public final static RunningState RUNNING_STATE = new RunningState();
//In the stop state, the elevator can open the door and run
public final static StoppingState STOPPING_STATE = new StoppingState();
//Define a current elevator state
private LiftState liftState;
public LiftState getLiftState() {
return this.liftState;
}
public void setLiftState(LiftState liftState) {
//Current environmental changes
this.liftState = liftState;
//Notify the current environment to each implementation class
this.liftState.setContext(this);
}
public void open() {
this.liftState.open();
}
public void close() {
this.liftState.close();
}
public void run() {
this.liftState.run();
}
public void stop() {
this.liftState.stop();
}
}
OpeningState
package com.zhuang.state.after;
/**
* @Classname OpeningState
*@ description open status
* @Date 2021/3/31 10:51
* @Created by dell
*/
public class OpeningState extends LiftState {
//Of course, it can be turned off when it is turned on. I just want to test the opening and closing function of the elevator door
@Override
public void open() {
System. out. Println ("elevator door open...);
}
@Override
public void close() {
//Status modification
super.context.setLiftState(Context.CLOSEING_STATE);
//The action is delegated to closestate, that is, it is delegated to the subclass of closengstate to execute the action
super.context.getLiftState().close();
}
//You can't run with the elevator door open. Nothing is done here
@Override
public void run() {
//do nothing
}
//The opening state has stopped
@Override
public void stop() {
//do nothing
}
}
ClosingState
package com.zhuang.state.after;
/**
* @Classname ClosingState
*@ description closed status
* @Date 2021/3/31 10:52
* @Created by dell
*/
public class ClosingState extends LiftState {
@Override
//The elevator door is closed, which is the action to be realized in the closed state
public void close() {
System. out. Println ("elevator door closed...);
}
//The elevator door is closed and then opened. I'm kidding you. That's allowed
@Override
public void open() {
super.context.setLiftState(Context.OPENNING_STATE);
super.context.open();
}
//It's perfectly normal to run when the elevator door is closed
@Override
public void run() {
super.context.setLiftState(Context.RUNNING_STATE);
super.context.run();
}
//When the elevator door is closed, I don't press the floor
@Override
public void stop() {
super.context.setLiftState(Context.STOPPING_STATE);
super.context.stop();
}
}
RunningState
package com.zhuang.state.after;
/**
* @Classname RunningState
*@ description running status
* @Date 2021/3/31 10:52
* @Created by dell
*/
public class RunningState extends LiftState {
@Override
public void open() {
//Do nothing
}
@Override
public void close() {
//Do nothing
}
@Override
public void run() {
System. out. Println ("elevator is running...);
}
@Override
public void stop() {
//Stop
super.context.setLiftState(Context.OPENNING_STATE);
super.context.stop();
}
}
StoppingState
package com.zhuang.state.after;
/**
* @Classname StoppingState
*@ description stop status
* @Date 2021/3/31 10:51
* @Created by dell
*/
public class StoppingState extends LiftState {
@Override
public void open() {
//Status modification
super.context.setLiftState(Context.OPENNING_STATE);
//The action is delegated to closestate to execute, that is, it is delegated to the subclass of closengstate to execute the action
super.context.getLiftState().open();
}
@Override
public void close() {
//Status modification
super.context.setLiftState(Context.CLOSEING_STATE);
//The action is delegated to closestate to execute, that is, it is delegated to the subclass of closengstate to execute the action
super.context.getLiftState().close();
}
@Override
public void run() {
//Status modification
super.context.setLiftState(Context.RUNNING_STATE);
//The action is delegated to closestate to execute, that is, it is delegated to the subclass of closengstate to execute the action
super.context.getLiftState().run();
}
@Override
public void stop() {
System. out. Println ("elevator stopped...);
}
}
Client
package com.zhuang.state.after;
/**
* @Classname Client
*@ description state mode test class
* @Date 2021/3/31 10:53
* @Created by dell
*/
public class Client {
public static void main(String[] args) {
//Door opening status
System. out. Println ("door opening status -- >");
Context context1 = new Context();
context1.setLiftState(new OpeningState());
context1.open();
context1.close();
context1.run();
context1.stop();
System.out.println("=========================");
//Closing state
System. out. Println ("closing status -- >");
Context context2 = new Context();
context2.setLiftState(new ClosingState());
context2.open();
context2.close();
context2.run();
context2.stop();
System.out.println("=========================");
//Running status
System. out. Println ("running status -- >");
Context context3 = new Context();
context3.setLiftState(new RunningState());
context3.open();
context3.close();
context3.run();
context3.stop();
System.out.println("=========================");
//Stop state
System. out. Println ("stop status -- >");
Context context4 = new Context();
context4.setLiftState(new StoppingState());
context4.open();
context4.close();
context4.run();
context4.stop();
}
}
25.3 application scenario of status mode
- When an object’s behavior depends on its state and it must change its behavior according to its state at run time, you can consider using state mode.
- An operation contains a huge branch structure, and these branches depend on the state of the object.
Write at the end
- If my article is useful to you, please give me some, thank you!
- If you have any questions, please point them out in the comment area!