3.10. Стан (State)

3.10.1. Призначення

Інкапсулює зміну поведінки тих самих методів залежно від стану об’єкта. Цей патерн допоможе витонченим способом змінити поведінку об’єкта під час виконання не вдаючись до великих умовних операторів.

3.10.2. Діаграма UML

Alt State UML Diagram

3.10.3. Код

Ви можете знайти цей код на 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. Тест

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}