Transcript Notes
Iterator Pattern
Traversing two
different collections
When bringing two previously
developed objects together, it
can be difficult to change an
implementation
Diner merger with PancakeHouse
Menu items -- same for both
collections -- this is key
public class DinerMenu implements Menu {
static final int MAX_ITEMS = 6;
int numberOfItems = 0;
MenuItem[] menuItems;
public DinerMenu() {
menuItems = new MenuItem[MAX_ITEMS];
addItem("Steamed Veggies and Brown Rice",
"Steamed vegetables over brown rice", true, 3.99);
addItem(…)
}
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;
}
}
public MenuItem[] getMenuItems() {
return menuItems;
}
// other menu methods here
}
public class PancakeHouseMenu implements Menu {
ArrayList menuItems;
public PancakeHouseMenu() {
menuItems = new ArrayList();
addItem("K&B's Pancake Breakfast",
"Pancakes with scrambled eggs, and toast",
true,
2.99);
…
}
public void addItem(String name, String description,
boolean vegetarian, double price)
{
MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
menuItems.add(menuItem);
}
public ArrayList getMenuItems() {
return menuItems;
}
// other menu methods here
}
public class Waitress {
PancakeHouseMenu pancakeHouseMenu;
ArrayList breakfastItems;
DinerMenu dinerMenu;
MenuItems[] lunchItems;
public Waitress(PancakeHouseMenu pancakeHouseMenu, DinerMenu dinerMenu) {
this.pancakeHouseMenu = pancakeHouseMenu;
breakfastItems = pancakeHouseMenu.getMenuItems();
this.dinerMenu = dinerMenu;
lunchItems = dinerMenu.getMenuItems();
}
public void printMenu(){
for (int i = 0; breakfastItems.size(); i++) {
MenuItem menuItem = (MenuItem)breakfastItems.get(i);
System.out.println(menuItem.getName()+” “+menuItem.getPrice());
System.out.println(menuItem.getDescription());
}
for (int i = 0; lunchItems.length; i++) {
MenuItem menuItem = lunchItems[i];
System.out.println(menuItem.getName()+” “+menuItem.getPrice());
System.out.println(menuItem.getDescription());
}
}
}
Waitress code
Need two loops to go through
the two collections
Will need to add another loop if
we add another collection
later
waitress has to know intimate
details of the collection code -bad form!
Let’s Encapsulate!
We can encapsulate the
iteration to avoid sharing too
much information
Iterator Interface
public interface Iterator
{
boolean hasNext();
Object next();
}
public class DinerMenuIterator implements Iterator {
MenuItem[] items;
int position = 0;
public DinerMenuIterator(MenuItem[] items) {
this.items = items;
}
public Object next() {
MenuItem menuItem = items[position];
position = position + 1;
return menuItem;
}
public boolean hasNext() {
if (position >= items.length || items[position] == null) {
return false;
} else {
return true;
}
}
}
public class DinerMenu implements Menu {
static final int MAX_ITEMS = 6;
int numberOfItems = 0;
MenuItem[] menuItems;
//constructor here
//addItem here
/* don’t need getMenuItems now that we have an Iterator!
public MenuItem[] getMenuItems() {
return menuItems;
}*/
public Iterator createIterator() {
return new DinerMenuIterator(menuItems);
}
// other menu methods here
}
New Waitress Code
public class Waitress {
PancakeHouseMenu pancakeHouseMenu;
DinerMenu dinerMenu;
public Waitress(PancakeHouseMenu pancakeHouseMenu, DinerMenu dinerMenu) {
this.pancakeHouseMenu = pancakeHouseMenu;
this.dinerMenu = dinerMenu;
}
public void printMenu() {
Iterator pancakeIterator = pancakeHouseMenu.createIterator();
Iterator dinerIterator = dinerMenu.createIterator();
System.out.println("MENU\n----\nBREAKFAST");
printMenu(pancakeIterator);
System.out.println("\nLUNCH");
printMenu(dinerIterator);
}
private void printMenu(Iterator iterator) {
while (iterator.hasNext()) {
MenuItem menuItem = (MenuItem)iterator.next();
System.out.print(menuItem.getName() + ", ");
System.out.print(menuItem.getPrice() + " -- ");
System.out.println(menuItem.getDescription());
}
}
//other methods
}
Compare and contrast
Waitresses
Old
Waitress must know
about menu
implementation
Needs 2 loops
new
Menus are
encapsulated
Waitress bound to
concrete classes
(MenuItem[] and
ArrayList)
Waitress now uses an
interface (Iterator)
Need 1 loop
Java.util.iterator
Now that we’ve built an iterator
from scratch, we can learn about
Java’s Iterator interface
hasNext()
Next()
remove()
Optional -- in unsupported must
throw
Java.lang.unsupportedOperationExc
eption
Updating menus
import java.util.ArrayList;
import java.util.Iterator;
public class PancakeHouseMenu implements Menu {
ArrayList menuItems;
//constructor here
public Iterator createIterator() {
return menuItems.iterator();
}
// other menu methods here
}
ArrayList already implements the Iterator interface
import java.util.Iterator;
public class DinerMenuIterator implements Iterator {
MenuItem[] list;
int position = 0;
public DinerMenuIterator(MenuItem[] list) {//constructor here }
public Object next() { //current implemenation }
public boolean hasNext() { //current implementation }
public void remove() {
if (position <= 0) {
throw new IllegalStateException
("You can't remove an item until you've done at least one
next()");
}
if (list[position-1] != null) {
for (int i = position-1; i < (list.length-1); i++) {
list[i] = list[i+1];
}
list[list.length-1] = null;
}
}
}
Updating waitress with
menu interface
public interface Menu{
public Iterator createIterator();
}
Add “implements Menu” to
DinerMenu and
PancakeHouseMenu
Then…
import java.util.Iterator;
public class Waitress {
Menu pancakeHouseMenu;
Menu dinerMenu;
public Waitress(Menu pancakeHouseMenu, Menu dinerMenu) {
this.pancakeHouseMenu = pancakeHouseMenu;
this.dinerMenu = dinerMenu;
}
public void printMenu() {
Iterator pancakeIterator = pancakeHouseMenu.createIterator();
Iterator dinerIterator = dinerMenu.createIterator();
System.out.println("MENU\n----\nBREAKFAST");
printMenu(pancakeIterator);
System.out.println("\nLUNCH");
printMenu(dinerIterator);
}
private void printMenu(Iterator iterator) {
while (iterator.hasNext()) {
MenuItem menuItem = (MenuItem)iterator.next();
System.out.print(menuItem.getName()+", ”+menuItem.getPrice()+ " -- ");
System.out.println(menuItem.getDescription());
}
}
//other methods
}
definitions
The Iterator Pattern provides a way
to access the elements of an
aggregate object sequentially
without exposing its underlying
representation.
Aggregate object - an object that is
a collection of other objects of the
same type, intended primarily for
storage
<<interface>>
Aggregate
createIterator()
Client
<<interface>>
Iterator
hasNext()
next()
remove()
ConcreteAggregate
ConcreteIterator
createIterator()
createIterator()
Iterator faq
Backwards iteration
Yes, but you need to add some
methods. Which?
Java also has ListIterator, similar
Ordering
Iterator does not imply ordering
Design Principle
sinlge responsibility
A class should have only one
reason to change
An aggregate that manages its own
collection AND iteration has two
opportunities to change.
Where?
Cohesion
A measure of how closely a
class supports a single purpose
or responsibility
High cohesion: designed around
a set of related functions
Low cohesion: designed around
unrelated functions
Cohesion examples
Book pg. 340
Iterator and Hashtable
Hash table accesses Iterator
indirectly
import java.util.*;
public class CafeMenu implements Menu {
Hashtable menuItems = new Hashtable();
public CafeMenu() {
//constructor code here
}
public void addItem(String name, String description,
boolean vegetarian, double price)
{
MenuItem menuItem = new MenuItem(name, description,
vegetarian, price);
menuItems.put(menuItem.getName(), menuItem);
}
public Iterator createIterator() {
return menuItems.values().iterator();
}
}
Iterators and
Collections
Java Colleections Framework
Vector, LinkedLIST, Stack, etc.
Java.util.collection interface
Each collection object knows
how to create its own iterator!
Sweet!
<<interface>>
Collection
add()
addAll()
clear()
contains()
containsAll()
equals()
hashCode()
isEmpty()
iterator()
remove()
removeAll()
reatainAll()
size()
toArray()
For/in is the new for
With java5 we have a new syntax
for iterating over collections
For(Object obj: collection)
No need to get the iterator
Generics
Type security
Composite
Iterator is related to the
Composite Pattern
We are not going to cover it
this semester, but you can read
about it in your book.