まず、状態を処理するために状態マネージャーが必要です。
<?php
class StateManager
{
protected $states = array();
public function registerState(StateInterface $state)
{
$this->states[$state->getName()] = $state;
}
public function getState($state)
{
if (!array_key_exists($state, $this->states)) {
throw new InvalidArgumentException();
}
return $this->states[$state];
}
}
次に、注文に対してアクションを実行できる注文マネージャーがあります。
<?php
class OrderManager
{
protected $stateManager;
public function ship(OrderInterface $order)
{
try {
$this->stateManager->getState($order->getState())->ship($order);
} catch (OperationNotAllowedException $exception) {
// However you want to handle the fact that the state can't be shipped
}
}
}
注文が特定の状態でアクションを実行できない場合にスローされる例外:
<?php
class OperationNotAllowedException extends Exception
{
}
状態のインターフェース:
<?php
interface StateInterface
{
public function getName();
// Then your normal functions
public function ship(OrderInterface $order);
public function cancel(OrderInterface $cancel);
public function addOrderLine(OrderInterface $order);
public function refund(OrderInterface $order);
}
ここで、アプリケーションをセットアップするとき:
$newOrderState = new NewState($database, $otherdependencies);
$stateManager->registerState($newOrderState);
注文オブジェクトは、状態のgetName
メソッドの1つが返すものと一致する、状態の文字列名を返すだけです。
この方法では、モックとテストを簡単に行うこともできます(これは、あらゆるアプリケーションにとって重要ですが、特に、人々のお金や製品を扱っているeコマースでは重要です)。