State Pattern

The State Pattern is an object behavioral pattern that implements a state machine in an object-oriented way. By using the State Pattern, each individual state is implemented as a derived class of the state pattern interface, and state transitions are implemented by calling methods defined by the pattern's superclass. The State Pattern can also be interpreted as the Strategy Pattern, as it allows for switching the current strategy by invoking methods defined in the pattern interface.

Description

In many cases, an object's behavior depends on one or more dynamically changing properties, which are called states, and such objects are known as stateful objects. The state of such an object is taken from a predefined series of values. When such an object interacts with external events, its internal state changes, leading to a change in the system's behavior. The State Pattern allows an object to change its behavior when its internal state changes. It is commonly used to resolve the issue of excessive if else conditional branches.

Advantages

  • Encapsulates transition rules.
  • Enumerates possible states, which requires determining the types of states before enumerating them.
  • Places all behaviors related to a state into one class and allows for easy addition of new states, simply by changing the object's state.
  • Allows the transition logic to be integrated with the state object, instead of a giant block of conditional statements.
  • Lets multiple context objects share a single state object, reducing the number of objects in the system.

Disadvantages

  • The use of the State Pattern inevitably increases the number of system classes and objects.
  • The structure and implementation of the State Pattern are relatively complex. Improper use can lead to confusion in program structure and code.
  • The State Pattern does not provide strong support for the "Open/Closed Principle." For state patterns that can switch states, adding new state classes requires modifying the source code responsible for state transitions; otherwise, the new state cannot be switched to. Furthermore, modifying the behavior of a state class also requires modifying the corresponding source code for that class.

Applicability

  • An object's behavior depends on its state (property), and can change its related behavior based on the state change.
  • The code contains a large number of conditional statements related to the object's state. The appearance of these conditional statements can reduce code maintainability and flexibility, making it difficult to add or remove states, and increasing the coupling between client classes and the class library. These conditional statements contain the object's behavior, and these conditions correspond to the object's various states.

Implementation

// Example: We can change the state of the input text
// If uppercase is selected, it will start printing in uppercase
// If lowercase is selected, it will print in lowercase, and so on

const upperCase = str => str.toUpperCase();
const lowerCase = str => str.toLowerCase();
const defaultTransform = str => str;

class TextEditor {
    constructor(transform) {
        this._transform = transform;
    }
    
    setTransform(transform) {
        this._transform = transform;
    }
    
    type(words) {
        console.log(this._transform(words));
    }
}

(function(){
    const editor = new TextEditor(defaultTransform);

    editor.type("First line"); // First line

    editor.setTransform(upperCase);

    editor.type("Second line"); // SECOND LINE
    editor.type("Third line"); // THIRD LINE

    editor.setTransform(lowerCase);

    editor.type("Fourth line"); // fourth line
    editor.type("Fifth line"); // fifth line
})();

Daily Question

https://github.com/WindrunnerMax/EveryDay

References

https://www.runoob.com/design-pattern/state-pattern.html https://github.com/sohamkamani/javascript-design-patterns-for-humans#-state https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/state.html