3.10. State

3.10.1. Scopo

Incapsulare comportamenti differenti per la medesima routine basata sullo stato di un oggetto. Può essere una maniera pulita per un oggetto di cambiare il suo comportamento a tempo di esecuzione evitando un monolite di espressioni condizionali.

3.10.2. Diagramma UML

Alt State UML Diagram

3.10.3. Codice

Potete trovare questo codice anche su 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}