Explanation of the Definition and Usage of the State Pattern of PHP Design Pattern

  • 2021-09-16 06:25:14
  • OfStack

This paper illustrates the definition and usage of state pattern of PHP design pattern. Share it for your reference, as follows:

What is the state design pattern

When the internal state of an object changes, it is allowed to change its behavior, and the object looks like it has changed its class.

The state pattern mainly solves the situation when the conditional expression that controls the state of an object is too complex. By transferring the judgment logic of states to a series of classes representing different states, the complex judgment logic can be simplified.

When to use state mode

Frequent changes in objects depend heavily on conditional statements. Conditional statements are not problematic on their own (such as switch statements or statements with else clauses), but they can be problematic if there are too many options to confuse the program at first, or if adding or changing options takes too much time, or even becomes a burden

For the state design pattern, each state has its own concrete class, which implements a common interface. Instead of looking at the control flow of the object, we consider it from another angle, that is, the state of the object.

A state machine is a model that focuses on different states, transitions from one state to another, and triggers that cause state changes.

Taking turning on and off lights as an example, the essence of the state model is divided into three points:

① State (turn off and turn on the lights)
② Change (from turning off the lights to turning on the lights, and from turning on the lights to turning off the lights)
③ Trigger (light switch)

Therefore, each state pattern requires one participant to track the state of the object. In the case of Light, Light needs to know what the current state is.

Example: Turn on and off the lights

Light.php


<?php
class Light
{
  private $offState; // Closed state 
  private $onState;  // Open state 
  private $currentState; // Current status 
  public function __construct()
  {
    $this->offState = new OffState($this);
    $this->onState = new OnState($this);
    // The starting state is closed Off
    $this->currentState = $this->offState;
  }
  // Invoke state method triggers 
  public function turnLightOn()
  {
    $this->currentState->turnLightOn();
  }
  public function turnLightOff()
  {
    $this->currentState->turnLightOff();
  }
  // Set the current state 
  public function setState(IState $state)
  {
    $this->currentState = $state;
  }
  // Get status 
  public function getOnState()
  {
    return $this->onState;
  }
  public function getOffState()
  {
    return $this->offState;
  }
}

In the constructor, Light instantiates two instances implemented by IState--1 corresponding off and 1 corresponding on


$this->offState = new OffState($this);
$this->onState = new OnState($this);

This instantiation process uses a recursion called self-reference (self-referral)

The argument in the constructor argument is written as $this, which is a reference to the Light class itself. The state class wants to take an instance of the Light class as an argument.

The setState method requires a state object as an argument to set a current state. Once a state is triggered, this state will send information to the Light class to specify the current state.

State instance

IState interface

IState.php


<?php
interface IState
{
  public function turnLightOn();
  public function turnLightOff();
}

The implementation class for this interface

OnState.php


<?php
class OnState implements IState
{
  private $light;
  public function __construct(Light $light)
  {
    $this->light = $light;
  }
  public function turnLightOn()
  {
    echo " The lights have been turned on -> Do not operate <br />";
  }
  public function turnLightOff()
  {
    echo " Light off ! You can't see handsome guys chenqionghe It's over !<br />";
    $this->light->setState($this->light->getOffState());
  }
}

OffState.php


<?php
class OffState implements IState
{
  private $light;
  public function __construct(Light $light)
  {
    $this->light = $light;
  }
  public function turnLightOn()
  {
    echo " Light on ! You can see handsome guys chenqionghe It's over !<br />";
    $this->light->setState($this->light->getOnState());
  }
  public function turnLightOff()
  {
    echo " The lights have been turned off -> Do not operate <br />";
  }
}

The default state is OffState, which must implement the IState methods turnLightOn and turnLightOff. Light calls the turnLightOn method and displays (lights on! You can see the handsome boy chenqionghe), and then set OnState to the current state. However, if you call OffState's turnLightOff method, you will only prompt that the light has been turned off and there will be no other actions.

Customer

All requests for Client are made through Light, and there is no direct connection between Client and any state classes, including the IState interface. The following Client shows requests that trigger all methods in both states.

Client.php


<?php
function __autoload($class_name)
{
  include_once $class_name.'.php';
}
class Client
{
  private $light;
  public function __construct()
  {
    $this->light = new Light();
    $this->light->turnLightOn();
    $this->light->turnLightOn();
    $this->light->turnLightOff();
    $this->light->turnLightOff();
  }
}
$worker = new Client();

Increase status

One important aspect of all design patterns is that they are easy to modify. Like other patterns, state patterns are easy to update and change. Add two more states to this lamp example: Brighter (Brighter) and Brightest (Brightest)

There are now four states, and the sequence has changed. The 'Off' (off) state can only be changed to the 'ON' (on) state, while the on state cannot be changed to the off state. The on state can only be changed to the 'Brighter' (brighter) state and the 'Brightest' (brightest) state. Only the brightest state can change to the OFF state.

Change interface

The first participant to change is the interface IState, which must specify methods that can be used to migrate to the brighter and brightest states.

IState.php


<?php
interface IState
{
  public function turnLightOn();
  public function turnLightOff();
  public function turnBrighter();
  public function turnBrightest();
}

All state classes must now contain these four methods, all of which need to be incorporated into the Light class.

Change state

When there are changes in the state design pattern, these new changes affect other aspects of the pattern as a whole. However, adding changes is fairly simple, with only one specific transition per state.

4 states

OnState.php


<?php
class OnState implements IState
{
  private $light;
  public function __construct(Light $light)
  {
    $this->light = $light;
  }
  public function turnLightOn()
  {
    echo " Illegal operation !<br />";
  }
  public function turnLightOff()
  {
    echo " Light off ! You can't see handsome guys chenqionghe It's over !<br />";
    $this->light->setState($this->light->getOffState());
  }
  public function turnBrighter()
  {
    echo " The lights are brighter ,  Look at handsome guys chenqionghe See it more clearly !<br />";
    $this->light->setState($this->light->getBrighterState());
  }
  public function turnBrightest()
  {
    echo " Illegal operation !<br />";
  }
}

OffState.php


<?php
class OffState implements IState
{
  private $light;
  public function __construct(Light $light)
  {
    $this->light = $light;
  }
  public function turnLightOn()
  {
    echo " Light on ! You can see handsome guys chenqionghe It's over !<br />";
    $this->light->setState($this->light->getOnState());
  }
  public function turnLightOff()
  {
    echo " Illegal operation !<br />";
  }
  public function turnBrighter()
  {
    echo " Illegal operation !<br />";
  }
  public function turnBrightest()
  {
    echo " Illegal operation !<br />";
  }
}

Brighter.php


<?php
class BrighterState implements IState
{
  private $light;
  public function __construct(Light $light)
  {
    $this->light = $light;
  }
  public function turnLightOn()
  {
    echo " Illegal operation !<br />";
  }
  public function turnLightOff()
  {
    echo " Illegal operation !<br />";
  }
  public function turnBrighter()
  {
    echo " Illegal operation !<br />";
  }
  public function turnBrightest()
  {
    echo " The light is at its brightest ,  Look at handsome guys chenqionghe Has been handsome to invincible !<br />";
    $this->light->setState($this->light->getBrightestState());
  }
}

Brightest.php


$this->offState = new OffState($this);
$this->onState = new OnState($this);

0

Update the Light class

Light.php


<?php
class Light
{
  private $offState; // Closed state 
  private $onState;  // Open state 
  private $brighterState; // Brighter state 
  private $brightestState;// Brightest state 
  private $currentState; // Current status 
  public function __construct()
  {
    $this->offState = new OffState($this);
    $this->onState = new OnState($this);
    $this->brighterState = new BrighterState($this);
    $this->brightestState = new BrightestState($this);
    // The starting state is closed Off
    $this->currentState = $this->offState;
  }
  // Invoke state method triggers 
  public function turnLightOn()
  {
    $this->currentState->turnLightOn();
  }
  public function turnLightOff()
  {
    $this->currentState->turnLightOff();
  }
  public function turnLightBrighter()
  {
    $this->currentState->turnBrighter();
  }
  public function turnLigthBrightest()
  {
    $this->currentState->turnBrightest();
  }
  // Set the current state 
  public function setState(IState $state)
  {
    $this->currentState = $state;
  }
  // Get status 
  public function getOnState()
  {
    return $this->onState;
  }
  public function getOffState()
  {
    return $this->offState;
  }
  public function getBrighterState()
  {
    return $this->brighterState;
  }
  public function getBrightestState()
  {
    return $this->brightestState;
  }
}

Update customer


<?php
function __autoload($class_name)
{
  include_once $class_name.'.php';
}
class Client
{
  private $light;
  public function __construct()
  {
    $this->light = new Light();
    $this->light->turnLightOn();
    $this->light->turnLightBrighter();
    $this->light->turnLigthBrightest();
    $this->light->turnLightOff();
    $this->light->turnLigthBrightest();
  }
}
$worker = new Client();

The results are as follows

Light on! You can see the handsome boy chenqionghe!
The lights are brighter, and you can see the handsome boy chenqionghe more clearly!
The light is the brightest. Look at the handsome boy chenqionghe!
Turn off the lights! I can't see the handsome boy chenqionghe!
Illegal operation!

Example of 9 grid movement

The movement of 9 squares is divided into 4 movements:

On (Up)
Under (Down)
Left (Left)
Right (Right)

For these moves, the rule is that you cannot move diagonally between cells. In addition, you can only move 1 cell at a time when you move from 1 cell to the next 1 cell

To use the state design pattern to create a 9-cell movement example,

Establish an interface

IMatrix.php


$this->offState = new OffState($this);
$this->onState = new OnState($this);

3

Although this state design pattern has nine states corresponding to nine cells, one state only needs four transitions at most

Context

For the four transition or move methods in the state, the context must provide corresponding methods to call these transition methods, and also complete the instantiation of each state.

Context.php


$this->offState = new OffState($this);
$this->onState = new OnState($this);

4

Status

The 9 states represent different cells in the 9-cell grid. In order to display only 1 cells, the corresponding number of cells arrived will be output respectively, so that the route through the matrix can be seen more clearly.

Cell1State


$this->offState = new OffState($this);
$this->onState = new OnState($this);

5

Cell2State


$this->offState = new OffState($this);
$this->onState = new OnState($this);

6

Cell3State


<?php
class Cell3State implements IMatrix
{
  private $context;
  public function __construct(Context $contextNow)
  {
    $this->context = $contextNow;
  }
  public function goLeft()
  {
    echo ' Walk to <strong>2</strong><br />';
    $this->context->setState($this->context->getCell2State());
  }
  public function goRight()
  {
    echo ' Illegal movement !<br />';
  }
  public function goUp()
  {
    echo ' Illegal movement !<br />';
  }
  public function goDown()
  {
    echo ' Walk to <strong>6</strong><br />';
    $this->context->setState($this->context->getCell6State());
  }
}

Cell4State


<?php
class Cell4State implements IMatrix
{
  private $context;
  public function __construct(Context $contextNow)
  {
    $this->context = $contextNow;
  }
  public function goLeft()
  {
    echo ' Illegal movement !<br />';
  }
  public function goRight()
  {
    echo ' Walk to <strong>5</strong><br />';
    $this->context->setState($this->context->getCell5State());
  }
  public function goUp()
  {
    echo ' Walk to <strong>1</strong><br />';
    $this->context->setState($this->context->getCell1State());
  }
  public function goDown()
  {
    echo ' Walk to <strong>7</strong><br />';
    $this->context->setState($this->context->getCell7State());
  }
}

Cell5State


$this->offState = new OffState($this);
$this->onState = new OnState($this);

9

Cell6State


<?php
class Cell6State implements IMatrix
{
  private $context;
  public function __construct(Context $contextNow)
  {
    $this->context = $contextNow;
  }
  public function goLeft()
  {
    echo ' Walk to <strong>5</strong><br />';
    $this->context->setState($this->context->getCell5State());
  }
  public function goRight()
  {
    echo ' Illegal movement !<br />';
  }
  public function goUp()
  {
    echo ' Walk to <strong>3</strong><br />';
    $this->context->setState($this->context->getCell3State());
  }
  public function goDown()
  {
    echo ' Walk to <strong>9</strong><br />';
    $this->context->setState($this->context->getCell9State());
  }
}

Cell7State


<?php
class Cell7State implements IMatrix
{
  private $context;
  public function __construct(Context $contextNow)
  {
    $this->context = $contextNow;
  }
  public function goLeft()
  {
    echo ' Illegal movement !<br />';
  }
  public function goRight()
  {
    echo ' Walk to <strong>8</strong><br />';
    $this->context->setState($this->context->getCell8State());
  }
  public function goUp()
  {
    echo ' Walk to <strong>4</strong><br />';
    $this->context->setState($this->context->getCell4State());
  }
  public function goDown()
  {
    echo ' Illegal movement !<br />';
  }
}

Cell8State


<?php
class Cell8State implements IMatrix
{
  private $context;
  public function __construct(Context $contextNow)
  {
    $this->context = $contextNow;
  }
  public function goLeft()
  {
    echo ' Walk to <strong>7</strong><br />';
    $this->context->setState($this->context->getCell7State());
  }
  public function goRight()
  {
    echo ' Walk to <strong>9</strong><br />';
    $this->context->setState($this->context->getCell9State());
  }
  public function goUp()
  {
    echo ' Walk to <strong>5</strong><br />';
    $this->context->setState($this->context->getCell5State());
  }
  public function goDown()
  {
    echo ' Illegal movement !<br />';
  }
}

Cell9State


<?php
class Cell9State implements IMatrix
{
  private $context;
  public function __construct(Context $contextNow)
  {
    $this->context = $contextNow;
  }
  public function goLeft()
  {
    echo ' Walk to <strong>8</strong><br />';
    $this->context->setState($this->context->getCell8State());
  }
  public function goRight()
  {
    echo ' Illegal movement !<br />';
  }
  public function goUp()
  {
    echo ' Walk to <strong>6</strong><br />';
    $this->context->setState($this->context->getCell6State());
  }
  public function goDown()
  {
    echo ' Illegal movement !<br />';
  }
}

The real difficulty in using state design patterns effectively is to imagine what the real or simulated world is like

Customer Client

Let's move up, right, down, down, left and up from cell 5

Client.php


<?php
function __autoload($class_name)
{
  include_once $class_name.'.php';
}
class Client
{
  private $context;
  public function __construct()
  {
    $this->context = new Context();
    $this->context->doUp();
    $this->context->doRight();
    $this->context->doDown();
    $this->context->doDown();
    $this->context->doLeft();
    $this->context->doUp();
  }
}
$worker = new Client();

The results are as follows

Go to 2
Go to 3
Go to 6
Go to 9
Go to 8
Go to 5

State Mode and PHP

Many people regard the state design pattern as the main method to implement simulators and games. In general, This is indeed the goal of state patterns, but beyond that, state models (state engines) and state design patterns have many applications in PHP. When PHP is used to complete larger projects, including Facebook and WordPress, there will be more new features and current state requirements. For this constantly changing and growing situation, extensible state patterns can be used to manage it.

How an PHP developer creates a program that contains multiple states will determine the scope of use of state patterns. So not only do state machines have many applications in the gaming and simulation worlds, but actually state models have many more areas of application. As long as users of an PHP program use a limited set of states, developers can use state design patterns.

For more readers interested in PHP related content, please check the topics on this site: "Introduction to php Object-Oriented Programming", "Introduction to PHP Basic Syntax", "Encyclopedia of PHP Array (Array) Operation Skills", "Summary of Usage of php String (string)", "Introduction to php+mysql Database Operation" and "Summary of Common Database Operation Skills of php"

I hope this article is helpful to everyone's PHP programming.


Related articles: