ステート パターン

State Pattern

State パターン | デザインパターン

2022年9年24日
デザインパターン State PHP
...

オライリージャパンによる Head First シリーズ デザインパターン(第2版)第10章 State パターンを、 PHPで書き直してみようという試みです。

State.php

 
namespace State;

interface State {

  public function insertQuarter () : void;
  public function ejectQuarter () : void;
  public function turnCrunk () : void;
  public function dispose () : void;

}
 

SoldOutState.php

 
namespace State;

class SoldOutState implements State {

  public GumballMachine $gumballMachine;

  public function __construct (GumballMachine $gumballMachine) {

    $this->gumballMachine = $gumballMachine;

  }

  public function insertQuarter () : void {

    echo '25セント投入することはできません。売り切れです' . "\n";

  }

  public function ejectQuarter () : void {

    echo '返金できません。まだ25セントを投入していません。' . "\n";

  }

  public function turnCrunk () : void {

    echo 'ハンドルを回しましたが、ガムボールがありません。' . "\n";

  }

  public function dispose () : void {

    echo 'ガムボールが出せません。' . "\n";

  }

}
 

NoQuarterState.php

 
namespace State;

class NoQuarterState implements State {

  public GumballMachine $gumballMachine;

  public function __construct (GumballMachine $gumballMachine) {

    $this->gumballMachine = $gumballMachine;

  }

  public function insertQuarter () : void {

    echo '25セント投入しました。' . "\n";
    $this->gumballMachine->setState($this->gumballMachine->getHasQuarterState());

  }

  public function ejectQuarter () : void {

    echo '25セント投入していません。' . "\n";

  }

  public function turnCrunk () : void {

    echo 'ハンドルを回しましたが、25セントを投入していません。' . "\n";

  }

  public function dispose () : void {

    echo 'まずお金を払う必要があります。' . "\n";

  }

}
 

SoldState.php

 
namespace State;

class SoldState implements State {

  public GumballMachine $gumballMachine;

  public function __construct (GumballMachine $gumballMachine) {

    $this->gumballMachine = $gumballMachine;

  }

  public function insertQuarter () : void {

    echo 'お待ちください。ガムボールを出す準備をしています。' . "\n";

  }

  public function ejectQuarter () : void {

    echo '申し訳ありません。既にハンドルを回しています。' . "\n";

  }

  public function turnCrunk () : void {

    echo '1回回してもガムボールをもう一つ手に入れることはできません。' . "\n";

  }

  public function dispose () : void {

    $this->gumballMachine->releaseBall();

    if ($this->gumballMachine->getCount() > 0) {

      $this->gumballMachine->setState($this->gumballMachine->getNoQuarterState());

    } else {

      echo 'おっと、ガムボールがなくなりました。' . "\n";
      $this->gumballMachine->setState($this->gumballMachine->getSoldOutState());

    }

  }

}
 

WinnerState.php

 
namespace State;

class WinnerState implements State {

  public GumballMachine $gumballMachine;

  public function __construct (GumballMachine $gumballMachine) {

    $this->gumballMachine = $gumballMachine;

  }

  public function insertQuarter () : void {

    echo 'お待ちください。ガムボールを出す準備をしています。' . "\n";

  }

  public function ejectQuarter () : void {

    echo '申し訳ありません。既にハンドルを回しています。' . "\n";

  }

  public function turnCrunk () : void {

    echo '1回回してもガムボールをもう一つ手に入れることはできません。' . "\n";

  }

  public function dispose () : void {

    $this->gumballMachine->releaseBall();

    if ($this->gumballMachine->getCount() == 0) {

      $this->gumballMachine->setState($this->gumballMachine->getSoldOutState());

    } else {

      $this->gumballMachine->releaseBall();

      echo '当たりです!25セントで2つのガムボールがもらえます。' . "\n";

      if ($this->gumballMachine->getCount() > 0) {

        $this->gumballMachine->setState($this->gumballMachine->getNoQuarterState());

      } else {

        echo 'おっと、ガムボールがなくなりました。' . "\n";
        $this->gumballMachine->setState($this->gumballMachine->getSoldOutState());

      }

    }

  }

}
 

GumballMachine.php

 
namespace State;

class GumballMachine {

  public State $soldOutState;
  public State $noQuarterState;
  public State $hasQuarterState;
  public State $soldState;
  public State $winnerState;

  public State $state;
  public int $count = 0;

  public function __construct (int $numberGumballs) {

    $this->soldOutState = new SoldOutState($this);
    $this->noQuarterState = new NoQuarterState($this);
    $this->hasQuarterState = new HasQuarterState($this);
    $this->soldState = new SoldState($this);
    $this->winnerState = new winnerState($this);

    $this->count = $numberGumballs;

    if ($numberGumballs > 0) {

      $this->state = $this->noQuarterState;

    } else {

      $this->state = $this->soldOutState;

    }

  }

  public function insertQuarter () : void {

    $this->state->insertQuarter();

  }

  public function ejectQuarter () : void {

    $this->state->ejectQuarter();

  }

  public function turnCrunk () : void {

    $this->state->turnCrunk();
    $this->state->dispose();

  }

  public function setState(State $state) : void {

    $this->state = $state;

  }

  public function releaseBall() : void {

    echo 'ガムボールがスロットから出てきます。' . "\n";

    if ($this->count != 0) {

      $this->count = $this->count - 1;

    }

  }

  public function getHasQuarterState() : State {

    return $this->hasQuarterState;

  }

  public function getNoQuarterState() : State {

    return $this->noQuarterState;

  }

  public function getSoldState() : State {

    return $this->soldState;

  }

  public function getSoldOutState() : State {

    return $this->soldOutState;

  }

  public function getWinnerState() : State {

    return $this->winnerState;

  }

  public function getCount() : int {

    return $this->count;

  }

}
 

index.php

 
use State\GumballMachine;

$gumballMachine = new GumballMachine(5);

echo '在庫:' . $gumballMachine->getCount() . '個のガムボール。';

$gumballMachine->insertQuarter();
$gumballMachine->turnCrunk();

echo '在庫:' . $gumballMachine->getCount() . '個のガムボール。';

$gumballMachine->insertQuarter();
$gumballMachine->turnCrunk();

echo '在庫:' . $gumballMachine->getCount() . '個のガムボール。';

$gumballMachine->insertQuarter();
$gumballMachine->turnCrunk();

echo '在庫:' . $gumballMachine->getCount() . '個のガムボール。';
 

出力結果

 
  在庫:5個のガムボール。

  25セント投入しました。
  ハンドルを回しました。
  ガムボールがスロットから出てきます。

  在庫:4個のガムボール。

  25セント投入しました。
  ハンドルを回しました。
  ガムボールがスロットから出てきます。
  ガムボールがスロットから出てきます。
  当たりです!25セントで2つのガムボールがもらえます。

  在庫:2個のガムボール。

  25セント投入しました。
  ハンドルを回しました。
  ガムボールがスロットから出てきます。

  在庫:1個のガムボール。
 

だてめがね
...
©️ ponpocopy

とある企業で社内SEをしています。 自身の学びが誰かの為になれば、という想いで日々ブログを更新中。 PHP(CakePHP・Laravel・FuelPHP), Pyhotn(Django・Flask), C#(ASP.NET、Unity) が好きです。