Состояние (англ. 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 ();
}
}