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