3.10. State

3.10.1. Propósito

Encapsula el comportamiento variable de la misma rutina en función del estado de un objeto. Esta puede ser una forma más limpia para que un objeto cambie su comportamiento en tiempo de ejecución sin tener que recurrir a declaraciones condicionales monolíticas de gran tamaño

3.10.2. Diagrama UML

Alt State UML Diagram

3.10.3. Código

Puedes encontrar el código en GitHub

OrderContext.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Behavioral\State;
 6
 7class OrderContext
 8{
 9    private State $state;
10
11    public static function create(): OrderContext
12    {
13        $order = new self();
14        $order->state = new StateCreated();
15
16        return $order;
17    }
18
19    public function setState(State $state)
20    {
21        $this->state = $state;
22    }
23
24    public function proceedToNext()
25    {
26        $this->state->proceedToNext($this);
27    }
28
29    public function toString()
30    {
31        return $this->state->toString();
32    }
33}

State.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Behavioral\State;
 6
 7interface State
 8{
 9    public function proceedToNext(OrderContext $context);
10
11    public function toString(): string;
12}

StateCreated.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Behavioral\State;
 6
 7class StateCreated implements State
 8{
 9    public function proceedToNext(OrderContext $context)
10    {
11        $context->setState(new StateShipped());
12    }
13
14    public function toString(): string
15    {
16        return 'created';
17    }
18}

StateShipped.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Behavioral\State;
 6
 7class StateShipped implements State
 8{
 9    public function proceedToNext(OrderContext $context)
10    {
11        $context->setState(new StateDone());
12    }
13
14    public function toString(): string
15    {
16        return 'shipped';
17    }
18}

StateDone.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Behavioral\State;
 6
 7class StateDone implements State
 8{
 9    public function proceedToNext(OrderContext $context)
10    {
11        // there is nothing more to do
12    }
13
14    public function toString(): string
15    {
16        return 'done';
17    }
18}

3.10.4. Test

Tests/StateTest.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Behavioral\State\Tests;
 6
 7use DesignPatterns\Behavioral\State\OrderContext;
 8use PHPUnit\Framework\TestCase;
 9
10class StateTest extends TestCase
11{
12    public function testIsCreatedWithStateCreated()
13    {
14        $orderContext = OrderContext::create();
15
16        $this->assertSame('created', $orderContext->toString());
17    }
18
19    public function testCanProceedToStateShipped()
20    {
21        $contextOrder = OrderContext::create();
22        $contextOrder->proceedToNext();
23
24        $this->assertSame('shipped', $contextOrder->toString());
25    }
26
27    public function testCanProceedToStateDone()
28    {
29        $contextOrder = OrderContext::create();
30        $contextOrder->proceedToNext();
31        $contextOrder->proceedToNext();
32
33        $this->assertSame('done', $contextOrder->toString());
34    }
35
36    public function testStateDoneIsTheLastPossibleState()
37    {
38        $contextOrder = OrderContext::create();
39        $contextOrder->proceedToNext();
40        $contextOrder->proceedToNext();
41        $contextOrder->proceedToNext();
42
43        $this->assertSame('done', $contextOrder->toString());
44    }
45}