Share
Fear Not the Machine of State!
Do your application’s objects have properties like ‘status’ or ‘state’, boolean properties like ‘active’, ‘paid’ or ‘published’, nullable timestamp properties like ‘paid_on’ or ‘published_at’? These are all good indicators that your project may benefit from the introduction of a State Machine. Proper use of a State Machine can mean less bugs, less undefined behavior, and a more clearly defined API to your object’s internal state, yet many developers are reluctant to use them in their projects, fearing unnecessary complexity, difficult integration or a steep learning curve. The good news is that these concerns are largely unfounded! Join us as we explore the State Machine’s theoretical underpinnings, examine its practical application including examples of its use in popular open source projects, and review available PHP resources for easily leveraging the power of the State Machine in your own projects.
willroth
Transcript
287 slides
-
State Pattern • Behavioral Pattern • Allows an object to
alter its behavior when its internal state changes, giving the appearance of changing class. -
Context: maintains an instance of the concrete state subclass that
defines current behavior. Abstract State: defines an interface for encapsulating all state behavior. Concrete State: implements the behavior associated with a state of the context. -
class Turnstyle { const LOCKED_STATE = 'locked'; const UNLOCKED_STATE =
'unlocked'; private $status; public function __construct($status = null) { $this->status = is_null($status) ? self::LOCKED_STATE : $status; } public function getStatus() { return $this->status; } public function pass() { $this->status = self::LOCKED_STATE; } public function coin() { $this->status = self::UNLOCKED_STATE; } } -
class Turnstyle { const LOCKED_STATE = 'locked'; const UNLOCKED_STATE =
'unlocked'; private $status; public function __construct($status = null) { $this->status = is_null($status) ? self::LOCKED_STATE : $status; } public function getStatus() { return $this->status; } public function pass() { $this->status = self::LOCKED_STATE; } public function coin() { $this->status = self::UNLOCKED_STATE; } } -
class Turnstyle { const LOCKED_STATE = 'locked'; const UNLOCKED_STATE =
'unlocked'; private $status; public function __construct($status = null) { $this->status = is_null($status) ? self::LOCKED_STATE : $status; } public function getStatus() { return $this->status; } public function pass() { $this->status = self::LOCKED_STATE; } public function coin() { $this->status = self::UNLOCKED_STATE; } } -
class Turnstyle { const LOCKED_STATE = 'locked'; const UNLOCKED_STATE =
'unlocked'; private $status; public function __construct($status = null) { $this->status = is_null($status) ? self::LOCKED_STATE : $status; } public function getStatus() { return $this->status; } public function pass() { $this->status = self::LOCKED_STATE; } public function coin() { $this->status = self::UNLOCKED_STATE; } } -
class Turnstyle { const LOCKED_STATE = 'locked'; const UNLOCKED_STATE =
'unlocked'; private $status; public function __construct($status = null) { $this->status = is_null($status) ? self::LOCKED_STATE : $status; } public function getStatus() { return $this->status; } public function pass() { $this->status = self::LOCKED_STATE; } public function coin() { $this->status = self::UNLOCKED_STATE; } } -
class Turnstyle { const LOCKED_STATE = 'locked'; const UNLOCKED_STATE =
'unlocked'; private $status; public function __construct($status = null) { $this->status = is_null($status) ? self::LOCKED_STATE : $status; } public function getStatus() { return $this->status; } public function pass() { $this->status = self::LOCKED_STATE; } public function coin() { $this->status = self::UNLOCKED_STATE; } } -
class Turnstyle { const LOCKED_STATE = 'locked'; const UNLOCKED_STATE =
'unlocked'; private $status; public function __construct($status = null) { $this->status = is_null($status) ? self::LOCKED_STATE : $status; } public function getStatus() { return $this->status; } public function pass() { $this->status = self::LOCKED_STATE; } public function coin() { $this->status = self::UNLOCKED_STATE; } } -
class Turnstyle { const LOCKED_STATE = 'locked'; const UNLOCKED_STATE =
'unlocked'; private $status; public function __construct($status = null) { $this->status = is_null($status) ? self::LOCKED_STATE : $status; } public function getStatus() { return $this->status; } public function pass() { $this->status = self::LOCKED_STATE; } public function coin() { $this->status = self::UNLOCKED_STATE; } } -
class Turnstyle { const LOCKED_STATE = 'locked'; const UNLOCKED_STATE =
'unlocked'; private $status; public function __construct($status = null) { $this->status = is_null($status) ? self::LOCKED_STATE : $status; } public function getStatus() { return $this->status; } public function pass() { $this->status = self::LOCKED_STATE; } public function coin() { $this->status = self::UNLOCKED_STATE; } } -
class Turnstyle { const LOCKED_STATE = 'locked'; const UNLOCKED_STATE =
'unlocked'; private $status; public function __construct($status = null) { $this->status = is_null($status) ? self::LOCKED_STATE : $status; } public function getStatus() { return $this->status; } public function pass() { $this->status = self::LOCKED_STATE; } public function coin() { $this->status = self::UNLOCKED_STATE; } } -
// truncated ... public function pass() { if ($this->status ==
self::LOCKED_STATE) { $this->alarm->sound(); } $this->status = self::LOCKED_STATE; } public function coin() { if ($this->status == self::UNLOCKED_STATE) { $this->coinVendor->refund(); } $this->status = self::UNLOCKED_STATE; } // truncated ... -
// truncated ... public function pass() { if ($this->status ==
self::LOCKED_STATE) { $this->alarm->sound(); } $this->status = self::LOCKED_STATE; } public function coin() { if ($this->status == self::UNLOCKED_STATE) { $this->coinVendor->refund(); } $this->status = self::UNLOCKED_STATE; } // truncated ... -
// truncated ... public function pass() { if ($this->status ==
self::LOCKED_STATE) { $this->alarm->sound(); } $this->status = self::LOCKED_STATE; } public function coin() { if ($this->status == self::UNLOCKED_STATE) { $this->coinVendor->refund(); } $this->status = self::UNLOCKED_STATE; } // truncated ... -
// truncated ... public function pass() { if ($this->status ==
self::LOCKED_STATE) { $this->alarm->sound(); } $this->status = self::LOCKED_STATE; } public function coin() { if ($this->status == self::UNLOCKED_STATE) { $this->coinVendor->refund(); } $this->status = self::UNLOCKED_STATE; } // truncated ... -
// truncated ... public function pass() { if ($this->status ==
self::LOCKED_STATE) { $this->alarm->sound(); } $this->status = self::LOCKED_STATE; } public function coin() { if ($this->status == self::UNLOCKED_STATE) { $this->coinVendor->refund(); } $this->status = self::UNLOCKED_STATE; } // truncated ... -
Locked Coin Unlock Pass Lock Unlocked Pass Alarm Coin Refund
Violation Ready -
Locked Coin Unlock Pass Lock Unlocked Pass Alarm Coin Refund
Violation Ready ResetAlarm -
Locked Coin Unlock Pass Lock Unlocked Pass Alarm Coin Refund
Violation Ready ResetAlarm Lock -
Locked Coin Unlock Pass Lock Unlocked Pass Alarm Coin Refund
Violation Ready ResetAlarm Lock -
Locked Coin Unlock Pass Lock Unlocked Pass Alarm Coin Refund
Violation Ready ResetAlarm Lock Coin -
Locked Coin Unlock Pass Lock Unlocked Pass Alarm Coin Refund
Violation Ready ResetAlarm Lock Coin Refund -
Locked Coin Unlock Pass Lock Unlocked Pass Alarm Coin Refund
Violation Ready ResetAlarm Lock Coin Refund -
Locked Coin Unlock Pass Lock Unlocked Pass Alarm Coin Refund
Violation Ready ResetAlarm Lock Coin Refund Pass -
Locked Coin Unlock Pass Lock Unlocked Pass Alarm Coin Refund
Violation Ready ResetAlarm Lock Coin Refund Pass -
Locked Coin Unlock Pass Lock Unlocked Pass Alarm Coin Refund
Violation Reset Ready ResetAlarm Lock Coin Refund Pass -
Locked Coin Unlock Pass Lock Unlocked Pass Alarm Coin Refund
Violation Reset ResetAlarm Ready ResetAlarm Lock Coin Refund Pass -
Locked Coin Unlock Pass Lock Unlocked Pass Alarm Coin Refund
Violation Reset ResetAlarm Ready ResetAlarm Lock Coin Refund Pass -
Locked Coin Unlock Pass Lock Unlocked Pass Alarm Coin Refund
Violation Reset ResetAlarm Ready ResetAlarm Lock Coin Refund Pass -
Locked Coin Unlock Pass Lock Unlocked Pass Alarm Coin Refund
Violation Reset ResetAlarm Ready ResetAlarm Lock Coin Refund Pass -
Locked Coin Unlock Pass Lock Unlocked Pass Alarm Coin Refund
Violation Reset ResetAlarm Ready ResetAlarm Lock NORMAL MODE Coin Refund Pass -
Locked Coin Unlock Pass Lock Unlocked Pass Alarm Coin Refund
Violation Reset ResetAlarm Ready ResetAlarm Lock NORMAL MODE Coin Refund Pass -
Locked Coin Unlock Pass Lock Unlocked Pass Alarm Coin Refund
Violation Reset ResetAlarm Ready ResetAlarm Lock NORMAL MODE DIAGNOSTIC MODE Coin Refund Pass -
Locked Coin Unlock Pass Lock Unlocked Pass Alarm Coin Refund
Violation Reset ResetAlarm Ready ResetAlarm Lock NORMAL MODE DIAGNOSTIC MODE H Coin Refund Pass -
Locked Coin Unlock Pass Lock Unlocked Pass Alarm Coin Refund
Violation Reset ResetAlarm Ready ResetAlarm Lock NORMAL MODE DIAGNOSTIC MODE H Coin Refund Pass -
class Turnstile { private $state; public $lockedState; public $unlockedState; public
function __construct(TurnstileState $state = null) { $this->lockedState = new LockedTurnstileState(); $this->unlockedState = new UnlockedTurnstileState(); $this->state = is_null($state) ? $this->lockedState : $state; } public function getState() { return $this->state; } public function setState(TurnstileState $state) { $this->state = $state; } public function pass() { $this->state->pass($this); } public function coin() { $this->state->coin($this); } } -
class Turnstile { private $state; public $lockedState; public $unlockedState; public
function __construct(TurnstileState $state = null) { $this->lockedState = new LockedTurnstileState(); $this->unlockedState = new UnlockedTurnstileState(); $this->state = is_null($state) ? $this->lockedState : $state; } public function getState() { return $this->state; } public function setState(TurnstileState $state) { $this->state = $state; } public function pass() { $this->state->pass($this); } public function coin() { $this->state->coin($this); } } -
class Turnstile { private $state; public $lockedState; public $unlockedState; public
function __construct(TurnstileState $state = null) { $this->lockedState = new LockedTurnstileState(); $this->unlockedState = new UnlockedTurnstileState(); $this->state = is_null($state) ? $this->lockedState : $state; } public function getState() { return $this->state; } public function setState(TurnstileState $state) { $this->state = $state; } public function pass() { $this->state->pass($this); } public function coin() { $this->state->coin($this); } } -
class Turnstile { private $state; public $lockedState; public $unlockedState; public
function __construct(TurnstileState $state = null) { $this->lockedState = new LockedTurnstileState(); $this->unlockedState = new UnlockedTurnstileState(); $this->state = is_null($state) ? $this->lockedState : $state; } public function getState() { return $this->state; } public function setState(TurnstileState $state) { $this->state = $state; } public function pass() { $this->state->pass($this); } public function coin() { $this->state->coin($this); } } -
class Turnstile { private $state; public $lockedState; public $unlockedState; public
function __construct(TurnstileState $state = null) { $this->lockedState = new LockedTurnstileState(); $this->unlockedState = new UnlockedTurnstileState(); $this->state = is_null($state) ? $this->lockedState : $state; } public function getState() { return $this->state; } public function setState(TurnstileState $state) { $this->state = $state; } public function pass() { $this->state->pass($this); } public function coin() { $this->state->coin($this); } } -
class Turnstile { private $state; public $lockedState; public $unlockedState; public
function __construct(TurnstileState $state = null) { $this->lockedState = new LockedTurnstileState(); $this->unlockedState = new UnlockedTurnstileState(); $this->state = is_null($state) ? $this->lockedState : $state; } public function getState() { return $this->state; } public function setState(TurnstileState $state) { $this->state = $state; } public function pass() { $this->state->pass($this); } public function coin() { $this->state->coin($this); } } -
class Turnstile { private $state; public $lockedState; public $unlockedState; public
function __construct(TurnstileState $state = null) { $this->lockedState = new LockedTurnstileState(); $this->unlockedState = new UnlockedTurnstileState(); $this->state = is_null($state) ? $this->lockedState : $state; } public function getState() { return $this->state; } public function setState(TurnstileState $state) { $this->state = $state; } public function pass() { $this->state->pass($this); } public function coin() { $this->state->coin($this); } } -
class Turnstile { private $state; public $lockedState; public $unlockedState; public
function __construct(TurnstileState $state = null) { $this->lockedState = new LockedTurnstileState(); $this->unlockedState = new UnlockedTurnstileState(); $this->state = is_null($state) ? $this->lockedState : $state; } public function getState() { return $this->state; } public function setState(TurnstileState $state) { $this->state = $state; } public function pass() { $this->state->pass($this); } public function coin() { $this->state->coin($this); } } -
class Turnstile { private $state; public $lockedState; public $unlockedState; public
function __construct(TurnstileState $state = null) { $this->lockedState = new LockedTurnstileState(); $this->unlockedState = new UnlockedTurnstileState(); $this->state = is_null($state) ? $this->lockedState : $state; } public function getState() { return $this->state; } public function setState(TurnstileState $state) { $this->state = $state; } public function pass() { $this->state->pass($this); } public function coin() { $this->state->coin($this); } } -
class Turnstile { private $state; public $lockedState; public $unlockedState; public
function __construct(TurnstileState $state = null) { $this->lockedState = new LockedTurnstileState(); $this->unlockedState = new UnlockedTurnstileState(); $this->state = is_null($state) ? $this->lockedState : $state; } public function getState() { return $this->state; } public function setState(TurnstileState $state) { $this->state = $state; } public function pass() { $this->state->pass($this); } public function coin() { $this->state->coin($this); } } -
class Turnstile { private $state; public $lockedState; public $unlockedState; public
function __construct(TurnstileState $state = null) { $this->lockedState = new LockedTurnstileState(); $this->unlockedState = new UnlockedTurnstileState(); $this->state = is_null($state) ? $this->lockedState : $state; } public function getState() { return $this->state; } public function setState(TurnstileState $state) { $this->state = $state; } public function pass() { $this->state->pass($this); } public function coin() { $this->state->coin($this); } } -
class Turnstile { private $state; public $lockedState; public $unlockedState; public
function __construct(TurnstileState $state = null) { $this->lockedState = new LockedTurnstileState(); $this->unlockedState = new UnlockedTurnstileState(); $this->state = is_null($state) ? $this->lockedState : $state; } public function getState() { return $this->state; } public function setState(TurnstileState $state) { $this->state = $state; } public function pass() { $this->state->pass($this); } public function coin() { $this->state->coin($this); } } -
class Turnstile { private $state; public $lockedState; public $unlockedState; public
function __construct(TurnstileState $state = null) { $this->lockedState = new LockedTurnstileState(); $this->unlockedState = new UnlockedTurnstileState(); $this->state = is_null($state) ? $this->lockedState : $state; } public function getState() { return $this->state; } public function setState(TurnstileState $state) { $this->state = $state; } public function pass() { $this->state->pass($this); } public function coin() { $this->state->coin($this); } } -
abstract class TurnstileState { public function pass(Turnstile $turnstile) { //empty
implementation } public function coin(Turnstile $turnstile) { //empty implementation } } -
abstract class TurnstileState { public function pass(Turnstile $turnstile) { //empty
implementation } public function coin(Turnstile $turnstile) { //empty implementation } } -
abstract class TurnstileState { public function pass(Turnstile $turnstile) { //empty
implementation } public function coin(Turnstile $turnstile) { //empty implementation } } -
abstract class TurnstileState { public function pass(Turnstile $turnstile) { //empty
implementation } public function coin(Turnstile $turnstile) { //empty implementation } } -
abstract class TurnstileState { public function pass(Turnstile $turnstile) { //empty
implementation } public function coin(Turnstile $turnstile) { //empty implementation } } -
class LockedTurnstileState extends TurnstileState { public function pass(Turnstile $turnstile) {
$turnstile->alarm->sound(); } public function coin(Turnstile $turnstile) { $turnstile->setState($turnstile->unlockedState); } } -
class LockedTurnstileState extends TurnstileState { public function pass(Turnstile $turnstile) {
$turnstile->alarm->sound(); } public function coin(Turnstile $turnstile) { $turnstile->setState($turnstile->unlockedState); } } -
class LockedTurnstileState extends TurnstileState { public function pass(Turnstile $turnstile) {
$turnstile->alarm->sound(); } public function coin(Turnstile $turnstile) { $turnstile->setState($turnstile->unlockedState); } } -
class LockedTurnstileState extends TurnstileState { public function pass(Turnstile $turnstile) {
$turnstile->alarm->sound(); } public function coin(Turnstile $turnstile) { $turnstile->setState($turnstile->unlockedState); } } -
class LockedTurnstileState extends TurnstileState { public function pass(Turnstile $turnstile) {
$turnstile->alarm->sound(); } public function coin(Turnstile $turnstile) { $turnstile->setState($turnstile->unlockedState); } } -
class LockedTurnstileState extends TurnstileState { public function pass(Turnstile $turnstile) {
$turnstile->alarm->sound(); } public function coin(Turnstile $turnstile) { $turnstile->setState($turnstile->unlockedState); } } -
class LockedTurnstileState extends TurnstileState { public function pass(Turnstile $turnstile) {
$turnstile->alarm->sound(); } public function coin(Turnstile $turnstile) { $turnstile->setState($turnstile->unlockedState); } } -
class LockedTurnstileState extends TurnstileState { public function pass(Turnstile $turnstile) {
$turnstile->alarm->sound(); } public function coin(Turnstile $turnstile) { $turnstile->setState($turnstile->unlockedState); } } -
class unlockedTurnstileState extends TurnstileState { public function pass(Turnstile $turnstile) {
$turnstile->setState($turnstile->lockedState); } public function coin(Turnstile $turnstile) { $turnstile->coinVendor->refund(); } } -
class unlockedTurnstileState extends TurnstileState { public function pass(Turnstile $turnstile) {
$turnstile->setState($turnstile->lockedState); } public function coin(Turnstile $turnstile) { $turnstile->coinVendor->refund(); } } -
class unlockedTurnstileState extends TurnstileState { public function pass(Turnstile $turnstile) {
$turnstile->setState($turnstile->lockedState); } public function coin(Turnstile $turnstile) { $turnstile->coinVendor->refund(); } } -
class unlockedTurnstileState extends TurnstileState { public function pass(Turnstile $turnstile) {
$turnstile->setState($turnstile->lockedState); } public function coin(Turnstile $turnstile) { $turnstile->coinVendor->refund(); } } -
class unlockedTurnstileState extends TurnstileState { public function pass(Turnstile $turnstile) {
$turnstile->setState($turnstile->lockedState); } public function coin(Turnstile $turnstile) { $turnstile->coinVendor->refund(); } } -
class unlockedTurnstileState extends TurnstileState { public function pass(Turnstile $turnstile) {
$turnstile->setState($turnstile->lockedState); } public function coin(Turnstile $turnstile) { $turnstile->coinVendor->refund(); } } -
class unlockedTurnstileState extends TurnstileState { public function pass(Turnstile $turnstile) {
$turnstile->setState($turnstile->lockedState); } public function coin(Turnstile $turnstile) { $turnstile->coinVendor->refund(); } } -
class unlockedTurnstileState extends TurnstileState { public function pass(Turnstile $turnstile) {
$turnstile->setState($turnstile->lockedState); } public function coin(Turnstile $turnstile) { $turnstile->coinVendor->refund(); } } -
Locked Coin Unlock Pass Lock Unlocked Pass Alarm Coin Refund
Violation Reset ResetAlarm Ready ResetAlarm Lock Coin Refund Pass -
class Turnstile { private $state; public $lockedState; public $unlockedState; public
$violationState; public function __construct(TurnstileState $state = null) { $this->lockedState = new LockedTurnstileState(); $this->unlockedState = new UnlockedTurnstileState(); $this->violationState = new ViolationTurnstileState(); $this->state = is_null($state) ? $this->lockedState : $state; } public function getState() { return $this->state; } public function setState(TurnstileState $state) { $this->state = $state; } public function pass() { $this->state->pass($this); } public function coin() { $this->state->coin($this); } public function reset() { $this->state->reset($this); } public function ready() { $this->state->ready($this); } } -
class Turnstile { private $state; public $lockedState; public $unlockedState; public
$violationState; public function __construct(TurnstileState $state = null) { $this->lockedState = new LockedTurnstileState(); $this->unlockedState = new UnlockedTurnstileState(); $this->violationState = new ViolationTurnstileState(); $this->state = is_null($state) ? $this->lockedState : $state; } public function getState() { return $this->state; } public function setState(TurnstileState $state) { $this->state = $state; } public function pass() { $this->state->pass($this); } public function coin() { $this->state->coin($this); } public function reset() { $this->state->reset($this); } public function ready() { $this->state->ready($this); } } -
class Turnstile { private $state; public $lockedState; public $unlockedState; public
$violationState; public function __construct(TurnstileState $state = null) { $this->lockedState = new LockedTurnstileState(); $this->unlockedState = new UnlockedTurnstileState(); $this->violationState = new ViolationTurnstileState(); $this->state = is_null($state) ? $this->lockedState : $state; } public function getState() { return $this->state; } public function setState(TurnstileState $state) { $this->state = $state; } public function pass() { $this->state->pass($this); } public function coin() { $this->state->coin($this); } public function reset() { $this->state->reset($this); } public function ready() { $this->state->ready($this); } } -
class Turnstile { private $state; public $lockedState; public $unlockedState; public
$violationState; public function __construct(TurnstileState $state = null) { $this->lockedState = new LockedTurnstileState(); $this->unlockedState = new UnlockedTurnstileState(); $this->violationState = new ViolationTurnstileState(); $this->state = is_null($state) ? $this->lockedState : $state; } public function getState() { return $this->state; } public function setState(TurnstileState $state) { $this->state = $state; } public function pass() { $this->state->pass($this); } public function coin() { $this->state->coin($this); } public function reset() { $this->state->reset($this); } public function ready() { $this->state->ready($this); } } -
class Turnstile { private $state; public $lockedState; public $unlockedState; public
$violationState; public function __construct(TurnstileState $state = null) { $this->lockedState = new LockedTurnstileState(); $this->unlockedState = new UnlockedTurnstileState(); $this->violationState = new ViolationTurnstileState(); $this->state = is_null($state) ? $this->lockedState : $state; } public function getState() { return $this->state; } public function setState(TurnstileState $state) { $this->state = $state; } public function pass() { $this->state->pass($this); } public function coin() { $this->state->coin($this); } public function reset() { $this->state->reset($this); } public function ready() { $this->state->ready($this); } } -
class Turnstile { private $state; public $lockedState; public $unlockedState; public
$violationState; public function __construct(TurnstileState $state = null) { $this->lockedState = new LockedTurnstileState(); $this->unlockedState = new UnlockedTurnstileState(); $this->violationState = new ViolationTurnstileState(); $this->state = is_null($state) ? $this->lockedState : $state; } public function getState() { return $this->state; } public function setState(TurnstileState $state) { $this->state = $state; } public function pass() { $this->state->pass($this); } public function coin() { $this->state->coin($this); } public function reset() { $this->state->reset($this); } public function ready() { $this->state->ready($this); } } -
class Turnstile { private $state; public $lockedState; public $unlockedState; public
$violationState; public function __construct(TurnstileState $state = null) { $this->lockedState = new LockedTurnstileState(); $this->unlockedState = new UnlockedTurnstileState(); $this->violationState = new ViolationTurnstileState(); $this->state = is_null($state) ? $this->lockedState : $state; } public function getState() { return $this->state; } public function setState(TurnstileState $state) { $this->state = $state; } public function pass() { $this->state->pass($this); } public function coin() { $this->state->coin($this); } public function reset() { $this->state->reset($this); } public function ready() { $this->state->ready($this); } } -
abstract class TurnstileState { public function pass(Turnstile $turnstile) { //empty
implementation } public function coin(Turnstile $turnstile) { //empty implementation } public function reset(Turnstile $turnstile) { //empty implementation } public function ready(Turnstile $turnstile) { //empty implementation } } -
abstract class TurnstileState { public function pass(Turnstile $turnstile) { //empty
implementation } public function coin(Turnstile $turnstile) { //empty implementation } public function reset(Turnstile $turnstile) { //empty implementation } public function ready(Turnstile $turnstile) { //empty implementation } } -
abstract class TurnstileState { public function pass(Turnstile $turnstile) { //empty
implementation } public function coin(Turnstile $turnstile) { //empty implementation } public function reset(Turnstile $turnstile) { //empty implementation } public function ready(Turnstile $turnstile) { //empty implementation } } -
abstract class TurnstileState { public function pass(Turnstile $turnstile) { //empty
implementation } public function coin(Turnstile $turnstile) { //empty implementation } public function reset(Turnstile $turnstile) { //empty implementation } public function ready(Turnstile $turnstile) { //empty implementation } } -
class violationTurnstileState implements TurnstileState { public function coin(Turnstile $turnstile) {
turnstile->coinVendor->refund(); } public function reset(Turnstile $turnstile) { $turnstile->alarm->reset(); } public function ready(Turnstile $turnstile) { $turnstile->alarm->reset(); $turnstile->setState($turnstile->unlockedTurnstileState); } } -
class violationTurnstileState implements TurnstileState { public function coin(Turnstile $turnstile) {
turnstile->coinVendor->refund(); } public function reset(Turnstile $turnstile) { $turnstile->alarm->reset(); } public function ready(Turnstile $turnstile) { $turnstile->alarm->reset(); $turnstile->setState($turnstile->unlockedTurnstileState); } } -
class violationTurnstileState implements TurnstileState { public function coin(Turnstile $turnstile) {
turnstile->coinVendor->refund(); } public function reset(Turnstile $turnstile) { $turnstile->alarm->reset(); } public function ready(Turnstile $turnstile) { $turnstile->alarm->reset(); $turnstile->setState($turnstile->unlockedTurnstileState); } } -
class violationTurnstileState implements TurnstileState { public function coin(Turnstile $turnstile) {
turnstile->coinVendor->refund(); } public function reset(Turnstile $turnstile) { $turnstile->alarm->reset(); } public function ready(Turnstile $turnstile) { $turnstile->alarm->reset(); $turnstile->setState($turnstile->unlockedTurnstileState); } } -
class violationTurnstileState implements TurnstileState { public function coin(Turnstile $turnstile) {
turnstile->coinVendor->refund(); } public function reset(Turnstile $turnstile) { $turnstile->alarm->reset(); } public function ready(Turnstile $turnstile) { $turnstile->alarm->reset(); $turnstile->setState($turnstile->unlockedTurnstileState); } } -
class violationTurnstileState implements TurnstileState { public function coin(Turnstile $turnstile) {
turnstile->coinVendor->refund(); } public function reset(Turnstile $turnstile) { $turnstile->alarm->reset(); } public function ready(Turnstile $turnstile) { $turnstile->alarm->reset(); $turnstile->setState($turnstile->unlockedTurnstileState); } } -
class lockedTurnstileState extends TurnstileState { public function pass(Turnstile $turnstile) {
$turnstile->alarm->sound(); $turnstile->setState($turnstile->violationState); } public function coin(Turnstile $turnstile) { $turnstile->setState($turnstile->unlockedState); } } -
class lockedTurnstileState extends TurnstileState { public function pass(Turnstile $turnstile) {
$turnstile->alarm->sound(); $turnstile->setState($turnstile->violationState); } public function coin(Turnstile $turnstile) { $turnstile->setState($turnstile->unlockedState); } } -
class lockedTurnstileState extends TurnstileState { public function pass(Turnstile $turnstile) {
$turnstile->alarm->sound(); $turnstile->setState($turnstile->violationState); } public function coin(Turnstile $turnstile) { $turnstile->setState($turnstile->unlockedState); } } -
class lockedTurnstileState extends TurnstileState { public function pass(Turnstile $turnstile) {
$turnstile->alarm->sound(); $turnstile->setState($turnstile->violationState); } public function coin(Turnstile $turnstile) { $turnstile->setState($turnstile->unlockedState); } } -
Locked Coin Unlock Pass Lock Unlocked Pass Alarm Coin Refund
Violation Reset ResetAlarm Ready ResetAlarm Lock Coin Refund Pass -
Locked Coin Unlock Pass Lock Unlocked Pass Alarm Coin Refund
Violation Reset ResetAlarm Ready ResetAlarm Lock NORMAL MODE DIAGNOSTIC MODE H Coin Refund Pass -
Extend the public API of the “context” & Abstract “state”
classes To include new event triggers -
Extend the public API of the “context” & Abstract “state”
classes To include new event triggers Create a concrete subclass of the abstract “state class” to encapsulate the new state logic -
Extend the public API of the “context” & Abstract “state”
classes To include new event triggers Create a concrete subclass of the abstract “state class” to encapsulate the new state logic ADD an instance of the new concrete “state” class as an instance variable on the “context” object -
• State Variables • $status • $state • Boolean Driven
Development • $active, $published -
• State Variables • $status • $state • Boolean Driven
Development • $active, $published • isActive(), isPublished() -
• State Variables • $status • $state • Boolean Driven
Development • $active, $published • isActive(), isPublished() • Nullable Timestamps -
• State Variables • $status • $state • Boolean Driven
Development • $active, $published • isActive(), isPublished() • Nullable Timestamps • Multipart Conditionals or Switches -
<?xml version="1.0" encoding="UTF-8"?> <specification> <configuration> <class name="Door"/> <interface name="DoorState"/> <abstractClass
name="AbstractDoorState"/> </configuration> <states> <state name="OpenDoorState" query="isOpen"/> <state name="ClosedDoorState" query="isClosed"/> <state name="LockedDoorState" query="isLocked"/> </states> <transitions> <transition from="ClosedDoorState" to="OpenDoorState" operation="open"/> <transition from="OpenDoorState" to="ClosedDoorState" operation="close"/> <transition from="ClosedDoorState" to="LockedDoorState" operation="lock"/> <transition from="LockedDoorState" to="ClosedDoorState" operation="unlock"/> </transitions> <operations> <operation name="open" allowed="canBeOpened" disallowed="cannotBeOpened"/> <operation name="close" allowed="canBeClosed" disallowed="cannotBeClosed"/> <operation name="lock" allowed="canBeLocked" disallowed="cannotBeLocked"/> <operation name="unlock" allowed="canBeUnlocked" disallowed="cannotBeUnlocked"/> </operations> </specification> -
OpenDoor [x] Can be closed [x] Cannot be opened [x]
Cannot be locked [x] Cannot be unlocked ClosedDoor [x] Cannot be closed [x] Can be opened [x] Can be locked [x] Cannot be unlocked LockedDoor [x] Cannot be closed [x] Cannot be opened [x] Cannot be locked [x] Can be unlocked -
class Door { private $state; public function __construct(DoorState $state) {
$this->setState($state); } public function open() { $this->setState($this->state->open()); } public function close() { $this->setState($this->state->close()); } public function lock() { $this->setState($this->state->lock()); } public function unlock() { $this->setState($this->state->unlock()); } private function setState(DoorState $state) { $this->state = $state; } } -
class Door { private $state; public function __construct(DoorState $state) {
$this->setState($state); } public function open() { $this->setState($this->state->open()); } public function close() { $this->setState($this->state->close()); } public function lock() { $this->setState($this->state->lock()); } public function unlock() { $this->setState($this->state->unlock()); } private function setState(DoorState $state) { $this->state = $state; } } -
class Door { private $state; public function __construct(DoorState $state) {
$this->setState($state); } public function open() { $this->setState($this->state->open()); } public function close() { $this->setState($this->state->close()); } public function lock() { $this->setState($this->state->lock()); } public function unlock() { $this->setState($this->state->unlock()); } private function setState(DoorState $state) { $this->state = $state; } } -
class Door { private $state; public function __construct(DoorState $state) {
$this->setState($state); } public function open() { $this->setState($this->state->open()); } public function close() { $this->setState($this->state->close()); } public function lock() { $this->setState($this->state->lock()); } public function unlock() { $this->setState($this->state->unlock()); } private function setState(DoorState $state) { $this->state = $state; } } -
class Door { private $state; public function __construct(DoorState $state) {
$this->setState($state); } public function open() { $this->setState($this->state->open()); } public function close() { $this->setState($this->state->close()); } public function lock() { $this->setState($this->state->lock()); } public function unlock() { $this->setState($this->state->unlock()); } private function setState(DoorState $state) { $this->state = $state; } } -
class Door { private $state; public function __construct(DoorState $state) {
$this->setState($state); } public function open() { $this->setState($this->state->open()); } public function close() { $this->setState($this->state->close()); } public function lock() { $this->setState($this->state->lock()); } public function unlock() { $this->setState($this->state->unlock()); } private function setState(DoorState $state) { $this->state = $state; } } -
class Door { private $state; public function __construct(DoorState $state) {
$this->setState($state); } public function open() { $this->setState($this->state->open()); } public function close() { $this->setState($this->state->close()); } public function lock() { $this->setState($this->state->lock()); } public function unlock() { $this->setState($this->state->unlock()); } private function setState(DoorState $state) { $this->state = $state; } } -
class Door { private $state; public function __construct(DoorState $state) {
$this->setState($state); } public function open() { $this->setState($this->state->open()); } public function close() { $this->setState($this->state->close()); } public function lock() { $this->setState($this->state->lock()); } public function unlock() { $this->setState($this->state->unlock()); } private function setState(DoorState $state) { $this->state = $state; } } -
class ClosedDoorState extends AbstractDoorState { public function open() { return
new OpenDoorState; } public function lock() { return new LockedDoorState; } } -
class ClosedDoorState extends AbstractDoorState { public function open() { return
new OpenDoorState; } public function lock() { return new LockedDoorState; } } -
class ClosedDoorState extends AbstractDoorState { public function open() { return
new OpenDoorState; } public function lock() { return new LockedDoorState; } } -
class ClosedDoorState extends AbstractDoorState { public function open() { return
new OpenDoorState; } public function lock() { return new LockedDoorState; } } -
class ClosedDoorState extends AbstractDoorState { public function open() { return
new OpenDoorState; } public function lock() { return new LockedDoorState; } } -
class ClosedDoorState extends AbstractDoorState { public function open() { return
new OpenDoorState; } public function lock() { return new LockedDoorState; } } -
• Context Object maintains a reference to the Stateful Object.
• States & Transitions are mapped and maintained by the Context Object. -
• Context Object maintains a reference to the Stateful Object.
• States & Transitions are mapped and maintained by the Context Object. • State Transitions are introduced externally rather than in response to Triggers. -
• Context Object maintains a reference to the Stateful Object.
• States & Transitions are mapped and maintained by the Context Object. • State Transitions are introduced externally rather than in response to Triggers. • The Context Object determines if Transitions are allowed. -
class Document implements Finite\StatefulInterface { private $state; public function getFiniteState()
{ return $this->state; } public function setFiniteState($state) { $this->state = $state; } } -
class Document implements Finite\StatefulInterface { private $state; public function getFiniteState()
{ return $this->state; } public function setFiniteState($state) { $this->state = $state; } } -
class Document implements Finite\StatefulInterface { private $state; public function getFiniteState()
{ return $this->state; } public function setFiniteState($state) { $this->state = $state; } } -
class Document implements Finite\StatefulInterface { private $state; public function getFiniteState()
{ return $this->state; } public function setFiniteState($state) { $this->state = $state; } } -
class Document implements Finite\StatefulInterface { private $state; public function getFiniteState()
{ return $this->state; } public function setFiniteState($state) { $this->state = $state; } } -
class Document implements Finite\StatefulInterface { private $state; public function getFiniteState()
{ return $this->state; } public function setFiniteState($state) { $this->state = $state; } } -
$stateMap = [ 'class' => 'Document', 'states' => [ 'draft'
=> ['type' => 'initial', 'properties' => []], 'proposed' => ['type' => 'normal', 'properties' => []], 'accepted' => ['type' => 'final', 'properties' => []], 'refused' => ['type' => 'final', 'properties' => []], ], 'transitions' => [ 'propose' => ['from' => ['draft'], 'to' => 'proposed'], 'accept' => ['from' => ['proposed'], 'to' => 'accepted'], 'refuse' => ['from' => ['proposed'], 'to' => 'refused'], ] ]; $stateMachine = new Finite\StateMachine\StateMachine; $loader->load(new Finite\Loader\ArrayLoader($stateMap)); $stateMachine->setObject(new Document); $stateMachine->initialize(); -
$stateMap = [ 'class' => 'Document', 'states' => [ 'draft'
=> ['type' => 'initial', 'properties' => []], 'proposed' => ['type' => 'normal', 'properties' => []], 'accepted' => ['type' => 'final', 'properties' => []], 'refused' => ['type' => 'final', 'properties' => []], ], 'transitions' => [ 'propose' => ['from' => ['draft'], 'to' => 'proposed'], 'accept' => ['from' => ['proposed'], 'to' => 'accepted'], 'refuse' => ['from' => ['proposed'], 'to' => 'refused'], ] ]; $stateMachine = new Finite\StateMachine\StateMachine; $loader->load(new Finite\Loader\ArrayLoader($stateMap)); $stateMachine->setObject(new Document); $stateMachine->initialize(); -
$stateMap = [ 'class' => 'Document', 'states' => [ 'draft'
=> ['type' => 'initial', 'properties' => []], 'proposed' => ['type' => 'normal', 'properties' => []], 'accepted' => ['type' => 'final', 'properties' => []], 'refused' => ['type' => 'final', 'properties' => []], ], 'transitions' => [ 'propose' => ['from' => ['draft'], 'to' => 'proposed'], 'accept' => ['from' => ['proposed'], 'to' => 'accepted'], 'refuse' => ['from' => ['proposed'], 'to' => 'refused'], ] ]; $stateMachine = new Finite\StateMachine\StateMachine; $loader->load(new Finite\Loader\ArrayLoader($stateMap)); $stateMachine->setObject(new Document); $stateMachine->initialize(); -
$stateMap = [ 'class' => 'Document', 'states' => [ 'draft'
=> ['type' => 'initial', 'properties' => []], 'proposed' => ['type' => 'normal', 'properties' => []], 'accepted' => ['type' => 'final', 'properties' => []], 'refused' => ['type' => 'final', 'properties' => []], ], 'transitions' => [ 'propose' => ['from' => ['draft'], 'to' => 'proposed'], 'accept' => ['from' => ['proposed'], 'to' => 'accepted'], 'refuse' => ['from' => ['proposed'], 'to' => 'refused'], ] ]; $stateMachine = new Finite\StateMachine\StateMachine; $loader->load(new Finite\Loader\ArrayLoader($stateMap)); $stateMachine->setObject(new Document); $stateMachine->initialize(); -
$stateMap = [ 'class' => 'Document', 'states' => [ 'draft'
=> ['type' => 'initial', 'properties' => []], 'proposed' => ['type' => 'normal', 'properties' => []], 'accepted' => ['type' => 'final', 'properties' => []], 'refused' => ['type' => 'final', 'properties' => []], ], 'transitions' => [ 'propose' => ['from' => ['draft'], 'to' => 'proposed'], 'accept' => ['from' => ['proposed'], 'to' => 'accepted'], 'refuse' => ['from' => ['proposed'], 'to' => 'refused'], ] ]; $stateMachine = new Finite\StateMachine\StateMachine; $loader->load(new Finite\Loader\ArrayLoader($stateMap)); $stateMachine->setObject(new Document); $stateMachine->initialize(); -
$stateMap = [ 'class' => 'Document', 'states' => [ 'draft'
=> ['type' => 'initial', 'properties' => []], 'proposed' => ['type' => 'normal', 'properties' => []], 'accepted' => ['type' => 'final', 'properties' => []], 'refused' => ['type' => 'final', 'properties' => []], ], 'transitions' => [ 'propose' => ['from' => ['draft'], 'to' => 'proposed'], 'accept' => ['from' => ['proposed'], 'to' => 'accepted'], 'refuse' => ['from' => ['proposed'], 'to' => 'refused'], ] ]; $stateMachine = new Finite\StateMachine\StateMachine; $loader->load(new Finite\Loader\ArrayLoader($stateMap)); $stateMachine->setObject(new Document); $stateMachine->initialize(); -
$stateMap = [ 'class' => 'Document', 'states' => [ 'draft'
=> ['type' => 'initial', 'properties' => []], 'proposed' => ['type' => 'normal', 'properties' => []], 'accepted' => ['type' => 'final', 'properties' => []], 'refused' => ['type' => 'final', 'properties' => []], ], 'transitions' => [ 'propose' => ['from' => ['draft'], 'to' => 'proposed'], 'accept' => ['from' => ['proposed'], 'to' => 'accepted'], 'refuse' => ['from' => ['proposed'], 'to' => 'refused'], ] ]; $stateMachine = new Finite\StateMachine\StateMachine; $loader->load(new Finite\Loader\ArrayLoader($stateMap)); $stateMachine->setObject(new Document); $stateMachine->initialize(); -
echo $stateMachine->getCurrentState(); // => "draft“ var_dump($stateMachine->can('accept')); // => bool(false) var_dump($stateMachine->can('propose'));
// => bool(true) $stateMachine->apply('propose'); echo $stateMachine->getCurrentState(); // => "proposed" -
echo $stateMachine->getCurrentState(); // => "draft“ var_dump($stateMachine->can('accept')); // => bool(false) var_dump($stateMachine->can('propose'));
// => bool(true) $stateMachine->apply('propose'); echo $stateMachine->getCurrentState(); // => "proposed" -
echo $stateMachine->getCurrentState(); // => "draft“ var_dump($stateMachine->can('accept')); // => bool(false) var_dump($stateMachine->can('propose'));
// => bool(true) $stateMachine->apply('propose'); echo $stateMachine->getCurrentState(); // => "proposed" -
echo $stateMachine->getCurrentState(); // => "draft“ var_dump($stateMachine->can('accept')); // => bool(false) var_dump($stateMachine->can('propose'));
// => bool(true) $stateMachine->apply('propose'); echo $stateMachine->getCurrentState(); // => "proposed" -
echo $stateMachine->getCurrentState(); // => "draft“ var_dump($stateMachine->can('accept')); // => bool(false) var_dump($stateMachine->can('propose'));
// => bool(true) $stateMachine->apply('propose'); echo $stateMachine->getCurrentState(); // => "proposed" -
• exceptionally complex? • subject to frequent change? Is Your
State & Transition Graph -
• exceptionally complex? • subject to frequent change? • externally
configurable? Is Your State & Transition Graph -
Follow Roughly the Same Design • Wrapper • Polymorphic “Wrappee”
• Delegation Solve the Same Problems -
Follow Roughly the Same Design • Wrapper • Polymorphic “Wrappee”
• Delegation Solve the Same Problems • Allow object to alter behavior when internal state changes -
Follow Roughly the Same Design • Wrapper • Polymorphic “Wrappee”
• Delegation Solve the Same Problems • Allow object to alter behavior when internal state changes Provide the Same Benefits -
Follow Roughly the Same Design • Wrapper • Polymorphic “Wrappee”
• Delegation Solve the Same Problems • Allow object to alter behavior when internal state changes Provide the Same Benefits • Increased Flexibility -
Follow Roughly the Same Design • Wrapper • Polymorphic “Wrappee”
• Delegation Solve the Same Problems • Allow object to alter behavior when internal state changes Provide the Same Benefits • Increased Flexibility • Increased Control -
Follow Roughly the Same Design • Wrapper • Polymorphic “Wrappee”
• Delegation Solve the Same Problems • Allow object to alter behavior when internal state changes Provide the Same Benefits • Increased Flexibility • Increased Control • Increased Visibility