Состояние (англ. State) — поведенческий шаблон проектирования.
Инкапсулирует изменение поведения одних и тех же методов в зависимости от состояния объекта. Этот шаблон поможет
изящным способом изменить поведение объекта во время выполнения, не прибегая к большим монолитным условным операторам.
Извне создаётся впечатление, что изменился класс объекта.
-
States
-
AbstractState.php
<?php namespace DesignPatterns\Behavioral\State\States; use DesignPatterns\Behavioral\State\Glass; use Exception; /** * Class AbstractState * @package DesignPatterns\Behavioral\State\States */ abstract class AbstractState implements StateInterface { const STATE = null; /** * @var Glass */ protected $glass; /** * AbstractState constructor. * * @param Glass $glass */ public function __construct(Glass $glass) { $this->glass = $glass; } /** * @return string */ protected function getGlassState(): string { $glassState = $this->glass->getState(); return $glassState::STATE; } /** * @return FillState * * @throws Exception */ abstract public function onFilled(): FillState; /** * @return EmptyState * * @throws Exception */ abstract public function onEmpty(): EmptyState; }
-
EmptyState.php
<?php namespace DesignPatterns\Behavioral\State\States; use Exception; /** * Class EmptyState * @package DesignPatterns\Behavioral\State\States */ class EmptyState extends AbstractState { const STATE = 'Empty'; /** * @return FillState * * @throws Exception */ public function onFilled(): FillState { if (static::STATE === $this->getGlassState()) { return new FillState($this->glass); } throw new Exception('Can\'t to fill filled glass.'); } /** * @return EmptyState * * @throws Exception */ public function onEmpty(): EmptyState { throw new Exception('Сan\'t pour the empty glass.'); } }
-
FillState.php
<?php namespace DesignPatterns\Behavioral\State\States; use Exception; /** * Class FillState * @package DesignPatterns\Behavioral\State\States */ class FillState extends AbstractState { const STATE = 'Fill'; /** * @throws Exception */ public function onFilled(): FillState { throw new Exception('Can\'t to fill filled glass.'); } /** * @return EmptyState * * @throws Exception */ public function onEmpty(): EmptyState { if (static::STATE === $this->getGlassState()) { return new EmptyState($this->glass); } throw new Exception('Сan\'t pour the empty glass.'); } }
-
StateInterface.php
<?php namespace DesignPatterns\Behavioral\State\States; use DesignPatterns\Behavioral\State\Glass; /** * Interface StateInterface * @package DesignPatterns\Behavioral\State\States */ interface StateInterface { /** * StateInterface constructor. * * @param Glass $glass */ public function __construct(Glass $glass); /** * @return FillState */ public function onFilled(): FillState; /** * @return EmptyState */ public function onEmpty(): EmptyState; }
-
-
Glass.php
<?php namespace DesignPatterns\Behavioral\State; use DesignPatterns\Behavioral\State\States\EmptyState; class Glass { protected $state; public function __construct() { $this->state = new EmptyState($this); } public function fill() { $this->state = $this->state->onFilled(); } public function pour() { $this->state = $this->state->onEmpty(); } public function getState() { return $this->state; } }
Test case:
StateTest.php
<?php
namespace DesignPatterns\Tests\Behavioral\State;
use DesignPatterns\Behavioral\State\Glass;
use Exception;
use PHPUnit_Framework_TestCase;
class StateTest extends PHPUnit_Framework_TestCase
{
public function testTryGlassInit()
{
$glass = new Glass();
$this->assertInstanceOf('DesignPatterns\Behavioral\State\States\EmptyState', $glass->getState());
$someGlass = new Glass();
$this->assertNotInstanceOf('DesignPatterns\Behavioral\State\States\FillState', $someGlass->getState());
}
public function testTryFillGlass()
{
$glass = new Glass();
$glass->fill();
$this->assertInstanceOf('DesignPatterns\Behavioral\State\States\FillState', $glass->getState());
$glass->pour();
$glass->fill();
$this->assertInstanceOf('DesignPatterns\Behavioral\State\States\FillState', $glass->getState());
}
public function testTryPourGlass()
{
$glass = new Glass();
$glass->fill();
$glass->pour();
$this->assertInstanceOf('DesignPatterns\Behavioral\State\States\EmptyState', $glass->getState());
$glass->fill();
$glass->pour();
$this->assertInstanceOf('DesignPatterns\Behavioral\State\States\EmptyState', $glass->getState());
}
public function testExceptionTryFillFilledGlass()
{
$this->expectException(Exception::class);
$glass = new Glass();
$glass->fill();
$glass->fill();
}
public function testExceptionTryPourTheEmptyGlass()
{
$this->expectException(Exception::class);
$glass = new Glass();
$glass->pour();
}
}