State Pattern - Object states and their transitions

1 Introduction

1.1. Overview

In a software system, some objects have multiple states like water, and these states can be converted to each other under certain circumstances, and the objects will also have different behaviors in different states. To better design these objects with multiple states, you can use a design pattern called the state pattern.

The state pattern is used to solve the state transition of complex objects in the system and the encapsulation of behavior in different states. The state pattern can be used when an object in the system has multiple states, transitions between these states are possible, and the object behaves differently in different states. The state mode separates the state of an object from the object and encapsulates it into a special state class, so that the state of the object can be changed flexibly. For the client, there is no need to care about the transition of the object state and the current state of the object, no matter what state the object is in, the client can process it consistently.

1.2. Definition

State Pattern: Allows an object to change its behavior when its internal state changes, the object appears to modify its class. Its alias is Objects for States, and the state pattern is an object behavior pattern.

2. Analysis

2.1, UML class diagram

The abstract state class and the concrete state class are introduced in the state pattern, which are the core of the state pattern, and their structure is shown in the figure below.
insert image description here
It can be seen that the following three roles are included in the state pattern structure diagram:

  1. Context (environmental class): The environmental class, also known as the context class, is an object with multiple states. Due to the diversity of the state of the environment class and the behavior of the object in different states, the state is separated to form a separate state class. An instance of the abstract state class State is maintained in the environment class, and this instance defines the current state. In the concrete implementation, it is an object of a State subclass.
  2. State (abstract state class): It is used to define an interface to encapsulate the behavior related to a specific state of the environment class. The methods corresponding to various states are declared in the abstract state class, and these methods are implemented in its subclasses. Since the behavior of objects in different states may be different, the implementation of methods in different subclasses may be different, and the same method can be written in the abstract state class.
  3. ConcreteState (concrete state class): It is a subclass of the abstract state class, and each subclass implements a behavior related to a state of the environment class. Each specific state class corresponds to a specific state of the environment class, and different specific state classes have different behaviors.

2.2. Code example

In the state pattern, the behavior of objects in different states is encapsulated into different state classes. In order to make the system more flexible and scalable, and to encapsulate the common behaviors in each state, the state needs to be abstracted, and an abstract state class role is introduced. The typical code is as follows:

/**
 * @Description: 抽象状态
 * @Author: yangyongbing
 * @CreateTime: 2023/08/03
 * @Version: 1.0
 */
abstract class State {
    
    
    // 声明抽象业务方法,不同的具体状态类可以有不同的方法实现
    public abstract void handle();
}

The business methods declared in the abstract state class are implemented in the subclass of the abstract state class, that is, the concrete state class. Different concrete state classes can provide completely different method implementations. In actual use, a state class may contain multiple business methods. If the implementation of some business methods in the concrete state class is exactly the same, these methods can be moved to the abstract state class to realize code reuse. A typical concrete status class code is as follows:

/**
 * @Description: 具体状态
 * @Author: yangyongbing
 * @CreateTime: 2023/08/03  19:45
 * @Version: 1.0
 */
public class ConcreteState extends State{
    
    
    @Override
    public void handle() {
    
    
        // 方法具体实现
    }
}

The environment class maintains a reference to the abstract state class. Different state objects can be injected into the environment class through the setState() method, and then the method of the state object is called in the business method of the environment class. The typical code is as follows:

/**
 * @Description: 环境类
 * @Author: yangyongbing
 * @CreateTime: 2023/08/03  19:46
 * @Version: 1.0
 */
public class Context {
    
    
    // 持有一个对抽象状态对象的引用
    private State state;
    // 其它属性值,该属性值的变化可能会导致对象状态发生变化
    private int value;

    // 设置状态对象
    public void setState(State state) {
    
    
        this.state = state;
    }

    public void request(){
    
    
        // 其它代码
        state.handle(); // 调用状态对象的业务方法
        // 其他代码
    }
}

The environment class is actually an object that really has a state. Here, the code related to the state in the environment class is extracted and encapsulated into a special state class.

During the use of the state pattern, the states of an object can also be converted to each other. There are usually two ways to implement state transitions:

  1. The environment class is responsible for the transition between states. At this point, the environment class also acts as a State Manager (State Manager) role. In the business method of the environment class, the state transition is realized by judging some attribute values, and a special method can also be provided for realizing attribute judgment and state transition. The code snippet is as follows:
public void changeState(){
    
    
   // 判断属性值,根据属性值进行状态转换
   if(value==0){
    
    
      this.setState(new ConcreteStateA());
   }else if(value==1){
    
    
       this.setState(new ConcreteStateB());
   }
}
  1. Concrete state classes are responsible for transitions between states. You can judge some attribute values ​​of the environment class in the business method of the specific state class, and then set a new state object for the environment class according to the situation to realize state transition. Similarly, a special method can also be provided to be responsible for judging attribute values ​​and state transitions. At this point, there will be a dependency or association relationship between the state class and the environment class, because the state class needs to access the attribute values ​​in the environment class. The code snippet is as follows:
public void changeState(Context ctx){
    
    
   // 判断属性值,根据属性值进行状态转换
   if(ctx.getValue()==1){
    
    
      this.setState(new ConcreteStateB());
   }else if(ctx.getValue()==2){
    
    
       this.setState(new ConcreteStateC());
   }
}

2.3. Shared state

In some cases, multiple environment objects may need to share the same state. If you want to implement multiple environment objects sharing one or more state objects in the system, you need to define these state objects as static member objects of the environment class.

The following uses a simple example to illustrate how to implement shared state. If a system requires that two switch objects are either both on or off, their states must be consistent when used. The switch can be switched from on to off, or from off to on.

You can use the state pattern to implement the design of the switch, and its structure is shown in the following figure:
insert image description here

3. Summary of state mode

The state pattern encapsulates the different behaviors of an object in different states in each state class. Environment objects can have different behaviors by setting different state objects, and the details of state transitions are transparent to the client, which facilitates the use of the client. In actual development, the state mode has a high frequency of use, and the state mode has been widely used in software such as workflow and games, such as the conversion of official document status and the upgrading of characters in games.

3.1. Main advantages

  1. Encapsulates state transition rules. In the state mode, the state transition code can be encapsulated in the environment class or the specific state class, and the state transition code can be managed centrally instead of scattered in each business method.
  2. Put all the behaviors related to a certain state into one class, and only need to inject a different state object to make the environment object have different behaviors.
  3. Allows state transition logic to be integrated with the state object, rather than providing one giant conditional statement block. The State pattern avoids the need for bulky conditional statements to interweave business methods and state transition code.
  4. Multiple environment objects can share a state object, thereby reducing the number of objects in the system.

3.2. Main disadvantages

  1. The use of state mode will inevitably increase the number of classes and objects in the system, resulting in increased system operating overhead.
  2. The program structure and implementation of the state mode are relatively complicated. If used improperly, the program structure and code will be confused, and the difficulty of system design will be increased.
  3. The state pattern does not support the open-closed principle very well. Adding a new state class requires modifying the source code responsible for the state transition, otherwise it cannot be converted to the newly added state; and modifying the behavior of a state class also requires modifying the source code of the corresponding class.

3.3. Usage scenarios

  1. The behavior of an object depends on its state (such as certain property values), and changes in state will cause changes in behavior.
  2. Include a large number of conditional statements related to the state of the object in the code. The appearance of these conditional statements will lead to poor maintainability and flexibility of the code, cannot easily add and delete states, and lead to enhanced coupling between the client class and the class library.

Guess you like

Origin blog.csdn.net/YYBDESHIJIE/article/details/132090330