イテレータ パターン

Iterator Pattern

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 -- インゲン豆、サルサ、グアカモーレ入りの大きなブリトー
 

だてめがね
...
©️ ponpocopy

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