Design mode 2-20 status mode

Posted by whizzkid-000 on Sun, 19 Dec 2021 07:24:00 +0100

1, Definition

The status mode is defined as follows:
Allow an object to alter its behavior when its internal state changes. the object will appear to change its class. (when an object's internal state changes, it is allowed to change its behavior, and the object looks like it has changed its class)

The general class diagram of the state pattern is shown above. As can be seen from the figure, there are three roles in the status mode:

  • State - abstract state role: an interface or abstract class, which is responsible for defining the object state and encapsulating the environment role to achieve state switching.
  • ConcreteSate - specific status role: each specific status has two responsibilities: behavior management of this status and processing of trend status. Generally speaking, it refers to what to do in this state and how to transition from this state to other states.
  • Context - environment role: defines the interface required by the client and is responsible for switching the specific state.

The core of state pattern: encapsulation. The change of state causes the change of behavior. From the outside, it looks as if the class corresponding to this object has changed.

2, General code

1. Abstract state role

public abstract class State{
    //Define an environment role to improve subclass access
    protected Context context;
    //Setting environment roles
    public void setContext(Context _context) {
        this.context = _context;
    }
    //Behavior 1
    public abstract void handle1();
    //Behavior 2
    public abstract void handle2();
}

2. Specific status role

public class ConcreteState1 extends State {
    @Override
    public void handle1() {
        //Logic that must be processed in this state
    }
    @Override
    public void handle2() {
        //Set the current status to state2
        super.context.setCurrentState(Context.STATE2);
        //Transition to state2 state, implemented by Context
        super.context.handle2();
    }
}
public class ConcreteState2 extends State {
    @Override
    public void handle1() {
        //Set the current status to state1
        super.context.setCurrentState(Context.STATE1);
        //Transition to state1 state, implemented by Context
        super.context.handle1();
    }
    @Override
    public void handle2() {
        //Logic that must be processed in this state
    }
}

Each specific state has two responsibilities: behavior management of this state and trend state processing.

3. Environmental role

public class Context {
   //Define status
    public final static State STATE1 = new ConcreteState1();
    public final static State STATE2 = new ConcreteState2();

    //current state
    private State currentState;
    public State getCurrentState() {
        return this.currentState;
    }
    public void setCurrentState(State currentState) {
        this.currentState= currentState;
        //Switching state
        this.currentState.setContext(this);
    }
    //Behavior entrustment
    public void handle1() {
        this.currentState.handle1();
    }
    @Override
    public void handle2() {
        this.currentState.handle2();
    }
}

Environmental roles have two unwritten constraints:

  1. State objects are declared as static constants, and several state objects have several static constants.
  2. The environment role has all behaviors defined by the abstract role, and the specific implementation uses the delegation method.

4. Customers

public class Client {

    public static void main(String[] args) {
    	//Define environmental roles
        Context context = new Context();
        //Initialization status
        context.setCurrentState(new ConcreteState1());
        //Behavior execution
        context.handle1();
        context.handle2();
    }
}

3, Practical examples

Because this mode is very important, but it is a little difficult to understand, so it is interesting to use a specific example to show it and run the code yourself. This example is the state change during elevator operation.

1. Abstract state role

public abstract class LiftState {
    //Define an environment role, that is, the function switching caused by the change of packaging state
    protected Context context;
    public void setContext(Context _context) {
        this.context = _context;
    }
    //First, the elevator door opens
    public abstract void open();
    //Elevator door closed
    public abstract void close();
    //Elevator operation
    public abstract void run();
    //Elevator stop
    public abstract void stop();
}

2. Specific status role

public class OpeningState extends LiftState{
    @Override
    public void open() {
        System.out.println("Elevator door open...");
    }
    @Override
    public void close() {
        //Status modification
        super.context.setLiftState(Context.closingState);
        //The action is delegated to CloseSate for execution
        super.context.getLiftState().close();
    }
    @Override
    public void run() {
        //The door won't work
    }
    @Override
    public void stop() {
        //It was a stop
    }
}

public class ClosingState extends LiftState{
    @Override
    public void open() {
        super.context.setLiftState(Context.openingState);
        super.context.getLiftState().open();
    }
    @Override
    public void close() {
        System.out.println("Elevator door closed...");
    }
    @Override
    public void run() {
        super.context.setLiftState(Context.runningState);
        super.context.getLiftState().run();
    }
    @Override
    public void stop() {
        //Not by floor
        super.context.setLiftState(Context.stoppingState);
        super.context.getLiftState().stop();
    }
}

public class RunningState extends LiftState{
    @Override
    public void open() {
        //In the running state, it cannot be turned on!
    }
    @Override
    public void close() {
        //It was closed
    }
    @Override
    public void run() {
        System.out.println("Elevator operation...");
    }
    @Override
    public void stop() {
        super.context.setLiftState(Context.stoppingState);
        super.context.getLiftState().stop();
    }
}

public class StoppingState extends LiftState{
    @Override
    public void open() {
        super.context.setLiftState(Context.openingState);
        super.context.getLiftState().open();
    }
    @Override
    public void close() {
        //It was closed
    }
    @Override
    public void run() {
        super.context.setLiftState(Context.runningState);
        super.context.getLiftState().run();
    }
    @Override
    public void stop() {
        System.out.println("Elevator stop...");
    }
}

3. Environmental role

public class Context {
    //Define all elevator states
    public final static OpeningState openingState = new OpeningState();
    public final static ClosingState closingState = new ClosingState();
    public final static RunningState runningState = new RunningState();
    public final static StoppingState stoppingState = new StoppingState();

    //Define a current elevator state
    private LiftState liftState;
    public LiftState getLiftState() {
        return this.liftState;
    }
    public void setLiftState(LiftState liftState) {
        this.liftState = liftState;
        //Notify each implementation class of the current environment
        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();
    }
}

4. Customers

public class Client {
    public static void main(String[] args) {
        Context context = new Context();
        context.setLiftState(new ClosingState());
        context.open();
        context.close();
        context.run();
        context.stop();
    }
}

The results are as follows:

Elevator door open...
Elevator door closed...
Elevator operation...
Elevator stop...

4, Application of state mode

1. Advantages and disadvantages of state mode

Advantages: clear structure, avoiding too many if statements; Follow design principles, including opening and closing principle and single responsibility principle; Good encapsulation,
Disadvantages: it is a kind of expansion problem, so the state is not easy to be too large, preferably no more than 5.

2. Usage scenario of status mode

  • Scenarios in which the behavior changes with the change of state: for example, the status of permission designers is different, and the results of executing the same behavior are different.
  • Substitutes for conditional and branch judgment statements

3. Best practices

When you need to reassemble several existing states in a certain order, you can use the construction mode + state mode.

Topics: Design Pattern