3.9. State
3.9.1. Purpose
Encapsulate varying behavior for the same routine based on an object’sstate. This can be a cleaner way for an object to change its behavior atruntime without resorting to large monolithic conditional statements.
3.9.2. UML Diagram
3.9.3. Code
You can also find this code on GitHub
OrderContext.php
- <?php
- namespace DesignPatterns\Behavioral\State;
- class OrderContext
- {
- /**
- * @var State
- */
- private $state;
- public static function create(): OrderContext
- {
- $order = new self();
- $order->state = new StateCreated();
- return $order;
- }
- public function setState(State $state)
- {
- $this->state = $state;
- }
- public function proceedToNext()
- {
- $this->state->proceedToNext($this);
- }
- public function toString()
- {
- return $this->state->toString();
- }
- }
State.php
- <?php
- namespace DesignPatterns\Behavioral\State;
- interface State
- {
- public function proceedToNext(OrderContext $context);
- public function toString(): string;
- }
StateCreated.php
- <?php
- namespace DesignPatterns\Behavioral\State;
- class StateCreated implements State
- {
- public function proceedToNext(OrderContext $context)
- {
- $context->setState(new StateShipped());
- }
- public function toString(): string
- {
- return 'created';
- }
- }
StateShipped.php
- <?php
- namespace DesignPatterns\Behavioral\State;
- class StateShipped implements State
- {
- public function proceedToNext(OrderContext $context)
- {
- $context->setState(new StateDone());
- }
- public function toString(): string
- {
- return 'shipped';
- }
- }
StateDone.php
- <?php
- namespace DesignPatterns\Behavioral\State;
- class StateDone implements State
- {
- public function proceedToNext(OrderContext $context)
- {
- // there is nothing more to do
- }
- public function toString(): string
- {
- return 'done';
- }
- }
3.9.4. Test
Tests/StateTest.php
- <?php
- namespace DesignPatterns\Behavioral\State\Tests;
- use DesignPatterns\Behavioral\State\OrderContext;
- use PHPUnit\Framework\TestCase;
- class StateTest extends TestCase
- {
- public function testIsCreatedWithStateCreated()
- {
- $orderContext = OrderContext::create();
- $this->assertEquals('created', $orderContext->toString());
- }
- public function testCanProceedToStateShipped()
- {
- $contextOrder = OrderContext::create();
- $contextOrder->proceedToNext();
- $this->assertEquals('shipped', $contextOrder->toString());
- }
- public function testCanProceedToStateDone()
- {
- $contextOrder = OrderContext::create();
- $contextOrder->proceedToNext();
- $contextOrder->proceedToNext();
- $this->assertEquals('done', $contextOrder->toString());
- }
- public function testStateDoneIsTheLastPossibleState()
- {
- $contextOrder = OrderContext::create();
- $contextOrder->proceedToNext();
- $contextOrder->proceedToNext();
- $contextOrder->proceedToNext();
- $this->assertEquals('done', $contextOrder->toString());
- }
- }