Iterator パターン | デザインパターン
2022年9年24日
デザインパターン
Iterator
PHP
オライリージャパンによる Head First シリーズ デザインパターン(第2版)第9章 Iterator パターンを、PHPで書き直してみようという試みです。
MenuItem.php
namespace Iterator;
class MenuItem {
public string $name;
public string $description;
public bool $vegetarian;
public float $price;
public function __construct(string $name, string $description, bool $vegetarian, float $price) {
$this->name = $name;
$this->description = $description;
$this->vegetarian = $vegetarian;
$this->price = $price;
}
public function getName() : string {
return $this->name;
}
public function getDescription() : string {
return $this->description;
}
public function getPrice() : float {
return $this->price;
}
public function isVegetarian() : bool {
return $this->vegetarian;
}
}
Menu.php
namespace Iterator;
interface Menu {
public function createIterator();
}
PancakeHouseMenu.php
namespace Iterator;
class PancakeHouseMenu implements Menu {
public array $menuItems;
public function __construct() {
self::addItem('K&Bのパンケーキ朝食', 'スクランブルエッグとトースト付きパンケーキ', true, 2.99);
self::addItem('いつものパンケーキ朝食', '卵焼きとソーセージ付きパンケーキ', false, 2.99);
self::addItem('ブルーベリーパンケーキ', '新鮮なブルーベリーを使ったパンケーキ', true, 3.49);
self::addItem('ワッフル', 'ブルーベリーかいちごの好きな方を乗せたワッフル', true, 3.59);
}
public function addItem(string $name, string $description, bool $vegetarian, float $price) : void {
$menuItem = new MenuItem($name, $description, $vegetarian, $price);
$this->menuItems[] = $menuItem;
}
public function createIterator() {
return new PancakeHouseMenuIterator($this->menuItems);
}
}
DinerMenu.php
namespace Iterator;
class DinerMenu implements Menu {
public int $MAX_ITEMS = 6;
public int $numberOfItems = 0;
public array $menuItems;
public function __construct() {
self::addItem('ベジタリアンBTL', 'レタス、トマト、(フェイク)ベーコンを挟んだ小麦パンサンドイッチ', true, 2.99);
self::addItem('BLT', 'レタス、トマト、ベーコンを挟んだ小麦パンサンドイッチ', false, 2.99);
self::addItem('本日のスープ', 'ポテトサラダを添えた本日のスープ', false, 3.29);
self::addItem('ホットドッグ', 'ザワークラウト、レリッシュ、玉ねぎ、チーズを挟んだホットドッグ', false, 3.05);
self::addItem('蒸し野菜と玄米', '玄米の上に蒸し野菜', true, 3.99);
self::addItem('パスタ', 'マリナラソーススパゲッティとサワードウパン', true, 3.89);
}
public function addItem(string $name, string $description, bool $vegetarian, float $price) : void {
if ($this->numberOfItems >= $this->MAX_ITEMS) {
echo 'すみません、メニューはいっぱいです!メニューに項目を追加できません。';
} else {
$menuItem = new MenuItem($name, $description, $vegetarian, $price);
$this->menuItems[$this->numberOfItems] = $menuItem;
$this->numberOfItems = $this->numberOfItems + 1;
}
}
public function createIterator() {
return new DinerMenuIterator($this->menuItems);
}
}
CafeMenu.php
namespace Iterator;
class CafeMenu implements Menu {
public array $menuItems;
public function __construct() {
self::addItem('野菜バーガーとフライドポテト', '小麦パンにレタスとトマトを挟んだ野菜バーガーとフライドポテト', true, 3.99);
self::addItem('本日のスープ', 'サラダがついた本日のスープ', false, 2.99);
self::addItem('ブリトー', 'インゲン豆、サルサ、グアカモーレ入りの大きなブリトー', true, 4.29);
}
public function addItem(string $name, string $description, bool $vegetarian, float $price) : void {
$menuItem = new MenuItem($name, $description, $vegetarian, $price);
$this->menuItems[] = $menuItem;
}
public function createIterator() {
return new PancakeHouseMenuIterator($this->menuItems);
}
}
Iterator.php
namespace Iterator;
interface Iterator {
public function hasNext() : bool;
public function next() : MenuItem;
}
PancakeHouseMenuIterator.php
namespace Iterator;
class PancakeHouseMenuIterator implements Iterator {
public int $position = 0;
public array $items;
public function __construct(array $items) {
$this->items = $items;
}
public function next() : MenuItem {
$menuItem = $this->items[$this->position++];
return $menuItem;
}
public function hasNext() : bool {
if ($this->position >= count($this->items)) {
return false;
} else {
return true;
}
}
}
DinerMenuIterator.php
namespace Iterator;
class DinerMenuIterator implements Iterator {
public int $position = 0;
public array $items;
public function __construct(array $items) {
$this->items = $items;
}
public function next() : MenuItem {
$menuItem = $this->items[$this->position++];
return $menuItem;
}
public function hasNext() : bool {
if ($this->position >= count($this->items)) {
return false;
} else {
return true;
}
}
}
CafeMenuIterator.php
namespace Iterator;
class CafeMenuIterator implements Iterator {
public int $position = 0;
public array $items;
public function __construct(array $items) {
$this->items = $items;
}
public function next() : MenuItem {
$menuItem = $this->items[$this->position++];
return $menuItem;
}
public function hasNext() : bool {
if ($this->position >= count($this->items)) {
return false;
} else {
return true;
}
}
}
Waitress.php
namespace Iterator;
class Waitress {
public array $menus;
public function __construct(array $menus) {
$this->menus = $menus;
}
public function printMenu() : void {
foreach($this->menus as $menus) {
$menu = $menus->createIterator();
self::_printMenu($menu);
}
}
private function _printMenu($iterator) : void {
while ($iterator->hasNext()) {
$menuItem = $iterator->next();
echo $menuItem->getName() . '、';
echo $menuItem->getPrice() . ' -- ';
echo $menuItem->getDescription();
echo "\n";
}
}
}
index.php
use Iterator\PancakeHouseMenu; use Iterator\DinerMenu; use Iterator\CafeMenu; use Iterator\Waitress; $pancakeHouseMenu = new PancakeHouseMenu(); $dinerMenu = new DinerMenu(); $cafeMenu = new CafeMenu(); $waitress = new Waitress([$pancakeHouseMenu, $dinerMenu, $cafeMenu]); $waitress->printMenu();
出力結果
K&Bのパンケーキ朝食、2.99 -- スクランブルエッグとトースト付きパンケーキ いつものパンケーキ朝食、2.99 -- 卵焼きとソーセージ付きパンケーキ ブルーベリーパンケーキ、3.49 -- 新鮮なブルーベリーを使ったパンケーキ ワッフル、3.59 -- ブルーベリーかいちごの好きな方を乗せたワッフル ベジタリアンBTL、2.99 -- レタス、トマト、(フェイク)ベーコンを挟んだ小麦パンサンドイッチ BLT、2.99 -- レタス、トマト、ベーコンを挟んだ小麦パンサンドイッチ 本日のスープ、3.29 -- ポテトサラダを添えた本日のスープ ホットドッグ、3.05 -- ザワークラウト、レリッシュ、玉ねぎ、チーズを挟んだホットドッグ 蒸し野菜と玄米、3.99 -- 玄米の上に蒸し野菜 パスタ、3.89 -- マリナラソーススパゲッティとサワードウパン 野菜バーガーとフライドポテト、3.99 -- 小麦パンにレタスとトマトを挟んだ野菜バーガーとフライドポテト 本日のスープ、2.99 -- サラダがついた本日のスープ ブリトー、4.29 -- インゲン豆、サルサ、グアカモーレ入りの大きなブリトー