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

ContextOrder.php

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

StateOrder.php

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

CreateOrder.php

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

ShippingOrder.php

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

OrderDone.php

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