3.10. Stan (State)

3.10.1. Przeznaczenie

Pozwala kapsułkować różne zachowania obiektu w ramach tego same procesu, w zależności od stanu w jakim obiekt aktualnie się znajduje. Dzięki temu nie musimy używać wielu instrukcji warunkowych.

3.10.2. Diagram UML

Alt State UML Diagram

3.10.3. Kod

Ten kod znajdziesz również na 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. Testy

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}