Design pattern learning 23 (Java implementation) — state pattern

Time:2022-3-12

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.

  1. 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”.
  2. 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.
  3. 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.

  1. The use of state mode will inevitably increase the number of classes and objects of the system.
  2. The structure and implementation of state mode are complex. Improper use will lead to confusion of program structure and code.
  3. 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

Design pattern learning 23 (Java implementation) -- state pattern

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
    }
}

Design pattern learning 23 (Java implementation) -- state pattern

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

Design pattern learning 23 (Java implementation) -- state pattern

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();


    }
}

Design pattern learning 23 (Java implementation) -- state pattern

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!