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個のガムボール。