Tags

,

The state pattern allows an object to behave in different ways based on its internal state. It is a behavioural design pattern. The experts agree that the object in question ideally has a related context object that handles the state. In addition, each of the different states implement the same state interface. The context object may also implement this interface. An abundance of switch statements around objects is indicative of technical debt with a potential state solution.

The state pattern resembles the strategy pattern. To see just how closely, here is a strategy example:

class CreditCardPayment {
      public function calcCosts($amount){
          return 0.05 * $amount;
      }
}

class PayByDebit {
      public function calcCosts($amount){
          return 0.20;
      }
}

class Costs {
    public $paymentType;
    public function __construct($paymentType) {
        $this->paymentType = $paymentType;
    }

    public function calcCosts($costs){
        return $this->paymentType->calcCosts($costs);
    }

}

$costsModel = new Costs(new creditCardPayment());

// the output is 0.5
echo $paymentCosts = $costsModel->calcCosts(10);

In this example the transaction costs of a payment depend on the type of payment used. The Costs object consumes a payment strategy and its calcCosts method can return the correct payment costs.

The state pattern equivalent looks like this:

interface StateInterface
{
    public function calcCosts($amount);
}

class CreditCardPayment implements StateInterface
{

    public function calcCosts($amount)
    {
        return 0.05 * $amount;
    }

}

class PayByDebit implements StateInterface
{

    public function calcCosts($amount)
    {
        return 0.20;
    }

}

class Costs
{
    public function calcCosts($amount)
    {
        return 0.3 * $amount;
    }
}

class CostsContext  implements StateInterface
{

    protected $costs;
    protected $paymentType;

    public function __construct($costs)
    {
        $this->costs = $costs;
    }

    public function setState($paymentType)
    {
        $this->paymentType = $paymentType;
    }

    public function getState()
    {
        return $this->paymentType;
    }

    public function calcCosts($amount)
    {
        if (is_null($this->paymentType)) {
            return $this->costs->calcCosts($amount);
        }
        return $this->paymentType->calcCosts($amount);
    }

}

$costsModel = new CostsContext(new Costs);
$costsModel->setState(new PayByDebit);
echo $paymentCosts = $costsModel->calcCosts(10);

The Costs object can perfectly well return transaction costs via the native calcCosts method but via the CostsContext object a context can be provided. The available states all implement the StateInterface. This example allows for the state not being set at all, which results in defaulting to the native calcCosts method of Costs.

State machines

And what about state machines? A finite-state machine is a type of computational method dealing with states. It is not a design pattern but it introduces a lot of terminology that can be helpful if you want to progress from the simple pattern described above. In this model each object can be in different states, moving between one state to another is called a transition. A state transition table explains how an input changes the current state, and what states are next available.

Sources

* https://en.wikipedia.org/wiki/State_pattern
* https://sourcemaking.com/design_patterns/state/php
* http://assessmentee.com/cheat/pattern/type/Strategy
* http://www.journaldev.com/1751/state-design-pattern-in-java-example-tutorial
* http://www.tutorialspoint.com/design_pattern/state_pattern.htm
* https://en.wikipedia.org/wiki/Finite-state_machine
* http://www.codeproject.com/Articles/509234/The-State-Design-Pattern-vs-State-Machine
* https://github.com/yohang/Finite
* http://www.shopify.com/technology/3383012-why-developers-should-be-force-fed-state-machines
* http://www.skorks.com/2011/09/why-developers-never-use-state-machines/
* http://www.giorgiosironi.com/2010/03/practical-php-patterns-state.html

Advertisements