Iterator Pattern

The Iterator Pattern provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

Iterator Pattern Diagram

Implementation

Creating a Aggregate interface:

public interface Menu {
	public Iterator<MenuItem> createIterator();
}

Creating a Concrete Aggregate:

public class DinerMenu implements Menu {
 
	static final int MAX_ITEMS = 6;
	
	int numberOfItems = 0;
	
	MenuItem[] menuItems;
 
	public DinerMenu() {
		menuItems = new MenuItem[MAX_ITEMS];	
		addItem("Vegetarian BLT", "(Fakin') Bacon with lettuce & tomato on whole wheat", true, 2.99);
		addItem("BLT", "Bacon with lettuce & tomato on whole wheat", false, 2.99);	
		addItem("Soup of the day", "Soup of the day, with a side of potato salad", false, 3.29);
	}
 
	public void addItem(String name, String description, boolean vegetarian, double price) {
		MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
		
		if (numberOfItems >= MAX_ITEMS) {
			System.err.println("Sorry, menu is full! Can't add item to menu");
		} else {
			menuItems[numberOfItems] = menuItem;
			numberOfItems = numberOfItems + 1;
		}
	}
	
	/* Array doesn't have built-in Iterator, so we create one */
	public Iterator<MenuItem> createIterator() {
		return new DinerMenuIterator(menuItems);
	}
}
public class PancakeHouseMenu implements Menu {
 
	ArrayList<MenuItem> menuItems;
	
	public PancakeHouseMenu() {
		menuItems = new ArrayList<MenuItem>();
		addItem("K&B's Pancake Breakfast", "Pancakes with scrambled eggs and toast", true, 2.99);
		addItem("Regular Pancake Breakfast", "Pancakes with fried eggs, sausage", false, 2.99);
	}
 
	public void addItem(String name, String description, boolean vegetarian, double price) {
		MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
		menuItems.add(menuItem);
	}
 
	/* Since ArrayList already has iterator method, we use that */
	public Iterator<MenuItem> createIterator() {
		return menuItems.iterator();
	}
}

Creating an Object which iterators iterates:

public class MenuItem {
 
	String name;
	String description;
	boolean vegetarian;
	double price;
 
	public MenuItem(String name, String description, boolean vegetarian, double price) {
		this.name = name;
		this.description = description;
		this.vegetarian = vegetarian;
		this.price = price;
	}
	
	public String getName() {
		return name;
	}
	
	public String getDescription() {
		return description;
	}
	
	public double getPrice() {
		return price;
	}
	
	public boolean isVegetarian() {
		return vegetarian;
	}
	
	public String toString() {
		return (name + ", $" + price + "\n " + description);
	}
}

Creating a Concrete Iterator:

public class DinerMenuIterator implements Iterator<MenuItem> {
	MenuItem[] items;
	int position = 0;
	
	public DinerMenuIterator(MenuItem[] items) {
		this.items = items;
	}
	
	public MenuItem next() {
		return items[position++];
	}
	
	public boolean hasNext() {
		return items.length > position;	
	}
 
	/* Optional for Java Iterator interface */
	public void remove() {
		throw new UnsupportedOperationException("Removing item is not allowed");
	}
}

Creating a Client:

public class Waitress {
	Menu pancakeHouseMenu;
	Menu dinerMenu;
	Menu cafeMenu;
 
	/* Set up menus for waitress */
	public Waitress(Menu pancakeHouseMenu, Menu dinerMenu, Menu cafeManu) {
		this.pancakeHouseMenu = pancakeHouseMenu;
		this.dinerMenu = dinerMenu;
		this.cafeMenu = cafeMenu;
	}
 
	/* Both utilizes Iterator interface */
	public void printMenu() {
		Iterator<MenuItem> pancakeIterator = pancakeHouseMenu.createIterator();
		Iterator<MenuItem> dinerIterator = dinerMenu.createIterator();
		Iterator<MenuItem> cafeIterator = cafeMenu.createIterator();
		
		/* We will solve the problem of having to iterate all these separately by utilizing Composite Pattern */
		System.out.println("MENU\n----\nBREAKFAST");
		printMenu(pancakeIterator);
		System.out.println("\nLUNCH");
		printMenu(dinerIterator);
		System.out.println("\nDINNER");
		printMenu(cafeIterator);
	}
 
	private void printMenu(Iterator<MenuItem> iterator) {
		while (iterator.hasNext()) {
			MenuItem menuItem = iterator.next();
			System.out.print(menuItem.getName() + ", ");
			System.out.print(menuItem.getPrice() + " -- ");
			System.out.println(menuItem.getDescription());
		}
	}
}

Testing:

public class MenuTestDrive {
	public static void main(String args[]) {
		/* Initialize Waitress with menus */
		Menu pancakeHouseMenu = new PancakeHouseMenu();
		Menu dinerMenu = new DinerMenu();
		CafeMenu cafeMenu = new CafeMenu();
		
		Waitress waitress = new Waitress(pancakeHouseMenu, dinerMenu, cafeMenu);
		/* Iterating each menu item */
		waitress.printMenu();
	}
}