この記事ではIteratorについてまとめます。
wikipediaによると「コンテナオブジェクトの要素を列挙する手段を独立させることによって、コンテナの内部仕様に依存しない反復子を提供する」とあります。
参考:Iteratorパターン
プログラミング言語には、配列、リスト、ハッシュテーブルなどデータを1つのオブジェクトとしてまとめる仕組みがあり、それぞれ適した使い方があり、このパターンはまとめたオブジェクトの要素に対して反復処理をを行います。
主な登場人物
no | 名前 | 役割 |
---|---|---|
1 | イテレータ | オブジェクトに順次アクセスするためのメソッドを定義するインタフェース |
2 | イテレータの具象クラス | オブジェクトに順次アクセスするメソッドを実装する |
3 | アグリゲート | コレクションのイテレータを返すメソッドを定義するインタフェース |
4 | アグリゲートの具象クラス | コレクションを保持していて、イテレータを返すメソッドを実装する |
パターンを実装する
複合商業施設のフードコードをイメージして、複数の飲食店メニューをデザインパターンに沿って実装したいと思います。ここでは例として「ハンバーガー」「お好み焼き」2店舗のメニューを定義します。また、それぞれの店舗で異なる形(配列とリスト)でデータを保持していることを想定します。
イテレータ
public interface Iterator {
boolean hasNext();
Object next();
}
イテレータの具象クラス
import java.util.ArrayList;
public class SandwichMenuIterator implements Iterator {
ArrayList<MenuItem> items = new ArrayList<>();
int position = 0;
public SandwichMenuIterator(ArrayList<MenuItem> items) {
this.items = items;
}
public Object next() {
MenuItem mi = items.get(this.position);
this.position++;
return mi;
}
public boolean hasNext() {
if (this.position >= this.items.size()) return false;
if (this.items.get(this.position) == null) return false;
return true;
}
}
public class OkonomiyakiMenuIterator implements Iterator {
MenuItem[] items;
int position = 0;
public OkonomiyakiMenuIterator(MenuItem[] items) {
this.items = items;
}
public Object next() {
MenuItem mi = this.items[this.position];
this.position++;
return mi;
}
public boolean hasNext() {
if (this.position >= this.items.length) return false;
if (this.items[this.position] == null) return false;
return true;
}
}
アグリゲート
public interface Menu {
public Iterator createIterator();
}
アグリゲートの具象クラス
import java.util.ArrayList;
public class SandwichMenu implements Menu {
ArrayList<MenuItem> menuItems = new ArrayList<>();
public SandwichMenu() {
addItem("ハンバーガー", "普通のサンドイッチ", true, 120);
addItem("チーズバーガー", "チーズを乗せたサンドイッチ", true, 240);
addItem("フィッシュバーガー", "魚のフライサンドイッチ", true, 320);
}
public void addItem(String name, String desc, Boolean coffee, Integer price) {
MenuItem mi = new MenuItem(name, desc, coffee, price);
menuItems.add(mi);
}
public Iterator createIterator() {
return new SandwichMenuIterator(menuItems);
}
public ArrayList<MenuItem> getMenuItems() {
return menuItems;
}
}
public class OkonomiyakiMenu implements Menu {
static final int MAX_ITEMS = 2;
MenuItem[] menuItems;
Integer cnt = 0;
public OkonomiyakiMenu() {
menuItems = new MenuItem[MAX_ITEMS];
addItem("豚玉", "地元の豚肉を仕様した焼き物", false, 600);
addItem("モダン焼き", "地元の野菜と麺を利用した焼き物", false, 750);
}
public void addItem(String name, String desc, Boolean coffee, Integer price) {
MenuItem mi = new MenuItem(name, desc, coffee, price);
menuItems[cnt] = mi;
cnt++;
}
public Iterator createIterator() {
return new OkonomiyakiMenuIterator(menuItems);
}
public MenuItem[] getMenuItems() {
return menuItems;
}
}
メニューのデータを保持するクラス
public class MenuItem {
String name;
String desc;
Boolean coffee;
Integer price;
public MenuItem(String name, String desc, Boolean coffee, Integer price) {
this.name = name;
this.desc = desc;
this.coffee = coffee;
this.price = price;
}
public String getName() { return name; }
public String getDesc() { return desc; }
public Boolean getCoffee() { return coffee; }
public Integer getPrice() { return price; }
}
メインクラス
public class Main {
public static void main(String args[]) {
SandwichMenu sm = new SandwichMenu();
OkonomiyakiMenu om = new OkonomiyakiMenu();
Iterator sandwichIterator = sm.createIterator();
Iterator okonomiyakiIterator = om.createIterator();
printMenu(sandwichIterator);
printMenu(okonomiyakiIterator);
}
public static void printMenu(Iterator iterator) {
while (iterator.hasNext()) {
MenuItem mi = (MenuItem)iterator.next();
System.out.print(mi.getName());
if(mi.getCoffee()) System.out.print("(コーヒー付き)");
System.out.println("," + mi.getPrice());
System.out.println("--" + mi.getDesc());
}
}
}
$java Main
ハンバーガー(コーヒー付き),120
--普通のサンドイッチ
チーズバーガー(コーヒー付き),240
--チーズを乗せたサンドイッチ
フィッシュバーガー(コーヒー付き),320
--魚のフライサンドイッチ
豚玉,600
--地元の豚肉を仕様した焼き物
モダン焼き,750
--地元の野菜と麺を利用した焼き物
Iteratorパターンはデータをまとめたオブジェクトに対して、順次アクセスするような機能を実装することです。今回は2つの異なるデータ型のオブジェクトに対して、それぞれのオブジェクトに順次アクセスするクラス(○○MenuIterator.java)を作成して画面上に出力するような例にしました。Java言語の「java.util.Collection」インタフェースにはIteratorメソッドが実装されているため、イメージしやすいかと思います。
参考:[Head Firstデザインパターン ―頭とからだで覚えるデザインパターン]
(https://www.amazon.co.jp/Head-First%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3-%E2%80%95%E9%A0%AD%E3%81%A8%E3%81%8B%E3%82%89%E3%81%A0%E3%81%A7%E8%A6%9A%E3%81%88%E3%82%8B%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E3%81%AE%E5%9F%BA%E6%9C%AC-Eric-Freeman/dp/4873112494)