my dog learned polymorphism*
The moose likes OO, Patterns, UML and Refactoring and the fly likes Couldn't get Menu Composite Iterator (HeadFirst Design Pattern) to work Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


JavaRanch » Java Forums » Engineering » OO, Patterns, UML and Refactoring
Bookmark "Couldn Watch "Couldn New topic
Author

Couldn't get Menu Composite Iterator (HeadFirst Design Pattern) to work

Jack Bush
Ranch Hand

Joined: Oct 20, 2006
Posts: 235
Hi All,

I am trying to run the corrected version Menu Compositor Iterator (Head First Design Pattern) by following the instructions from earlier posts ([url]http://www.coderanch.com/t/100049/OO-Patterns-UML-Refactoring/Head-First-Design-Patterns-Composite[/url]) but encountered the following Exception:

ALL MENUS, All menus combined
---------------------

PANCAKE HOUSE MENU, Breakfast
---------------------
K&B's Pancake Breakfast(v), 2.99
-- Pancakes with scrambled eggs, and toast
Regular Pancake Breakfast, 2.99
-- Pancakes with fried eggs, sausage
Blueberry Pancakes(v), 3.49
-- Pancakes made with fresh blueberries, and blueberry syrup
Waffles(v), 3.59
-- Waffles, with your choice of blueberries or strawberries

DINER MENU, Lunch
---------------------
Vegetarian BLT(v), 2.99
-- (Fakin') Bacon with lettuce & tomato on whole wheat
BLT, 2.99
-- Bacon with lettuce & tomato on whole wheat
Soup of the day, 3.29
-- A bowl of the soup of the day, with a side of potato salad
Hotdog, 3.05
-- A hot dog, with saurkraut, relish, onions, topped with cheese
Steamed Veggies and Brown Rice(v), 3.99
-- A medly of steamed vegetables over brown rice
Pasta(v), 3.89
-- Spaghetti with Marinara Sauce, and a slice of sourdough bread

DESSERT MENU, Dessert of course!
---------------------
Apple Pie(v), 1.59
-- Apple pie with a flakey crust, topped with vanilla icecream
Cheesecake(v), 1.99
-- Creamy New York cheesecake, with a chocolate graham crust
Sorbet(v), 1.89
-- A scoop of raspberry and a scoop of lime

CAFE MENU, Dinner
---------------------
Veggie Burger and Air Fries(v), 3.99
-- Veggie burger on a whole wheat bun, lettuce, tomato, and fries
Soup of the day, 3.69
-- A cup of the soup of the day, with a side salad
Burrito(v), 4.29
-- A large burrito, with whole pinto beans, salsa, guacamole

VEGETARIAN MENU
----
[color=red][b]Exception in thread "main" java.util.NoSuchElementException
at headfirst.composite.menuiterator.CompositeIterator.next(CompositeIterator.java:50)
at headfirst.composite.menuiterator.Waitress.printVegetarianMenu(Waitress.java:23)
at headfirst.composite.menuiterator.MenuTestDrive.main(MenuTestDrive.java:113)[/b][/color]Java Result: 1


Below are all the related code snippets:

[code]public abstract class MenuComponent {

public void add(MenuComponent menuComponent) {
throw new UnsupportedOperationException();
}
public void remove(MenuComponent menuComponent) {
throw new UnsupportedOperationException();
}
public MenuComponent getChild(int i) {
throw new UnsupportedOperationException();
}

public String getName() {
throw new UnsupportedOperationException();
}
public String getDescription() {
throw new UnsupportedOperationException();
}
public double getPrice() {
throw new UnsupportedOperationException();
}
public boolean isVegetarian() {
throw new UnsupportedOperationException();
}

public abstract Iterator createIterator();

public void print() {
throw new UnsupportedOperationException();
}
}
--------------------------------------------------------------------------------------------
public class Menu extends MenuComponent {

ArrayList menuComponents = new ArrayList();
String name;
String description;

public Menu(String name, String description) {
this.name = name;
this.description = description;
}

public void add(MenuComponent menuComponent) {
menuComponents.add(menuComponent);
}

public void remove(MenuComponent menuComponent) {
menuComponents.remove(menuComponent);
}

public MenuComponent getChild(int i) {
return (MenuComponent)menuComponents.get(i);
}

public String getName() {
return name;
}

public String getDescription() {
return description;
}


public Iterator createIterator() {
// return new CompositeIterator(this, menuComponents.iterator());
return menuComponents.iterator();
}


public void print() {
System.out.print("\n" + getName());
System.out.println(", " + getDescription());
System.out.println("---------------------");

Iterator iterator = menuComponents.iterator();
while (iterator.hasNext()) {
MenuComponent menuComponent =
(MenuComponent)iterator.next();
menuComponent.print();
}
}
}
--------------------------------------------------------------------------------------------
public class MenuItem extends MenuComponent {

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 Iterator createIterator() {
// return new NullIterator();
return new CompositeIterator(this);
}

public void print() {
System.out.print(" " + getName());
if (isVegetarian()) {
System.out.print("(v)");
}
System.out.println(", " + getPrice());
System.out.println(" -- " + getDescription());
}
--------------------------------------------------------------------------------------------
public class CompositeIterator implements Iterator {
boolean started = false;
MenuComponent parent;
Iterator childIterator = null;
Iterator subtreeIterator = null;

CompositeIterator(MenuComponent parent){
this.parent = parent;
}

@SuppressWarnings("unchecked")
CompositeIterator(MenuComponent parent, Iterator childIterator){
this(parent);
this.childIterator = childIterator;
}

@SuppressWarnings("unchecked")
public Object next() {
MenuComponent component = null;

if( started ) {
if( childIterator != null ) {

// current subtree expended?
if( subtreeIterator != null && ! subtreeIterator.hasNext())
subtreeIterator = null;

// another subtree needed and available?
if( subtreeIterator == null && childIterator.hasNext())
subtreeIterator =
((MenuComponent)childIterator.next()).createIterator();

// finally get it from subtree
if( subtreeIterator != null )
component = (MenuComponent)subtreeIterator.next();
}

} else {
// the root is the first node
started = true;
component = parent;
}

if(component == null)
throw new java.util.NoSuchElementException();

System.out.println( ">>>>> " + component.getName() + " of " + parent.getName() );
return component;
}

public boolean hasNext() {
// there is always the (first) node that created this iterator
if (! started) return true;

if(subtreeIterator != null && subtreeIterator.hasNext()) return true;

// if there is another child there is at least one other node
if(childIterator != null) return childIterator.hasNext();

return false;
}

public void remove() {
throw new UnsupportedOperationException();
}
}
--------------------------------------------------------------------------------------------
public class NullIterator implements Iterator {

public Object next() {
return null;
}

public boolean hasNext() {
return false;
}

public void remove() {
throw new UnsupportedOperationException();
}
}
--------------------------------------------------------------------------------------------
public class Waitress {
MenuComponent allMenus;

public Waitress(MenuComponent allMenus) {
this.allMenus = allMenus;
}

public void printMenu() {
allMenus.print();
}

public void printVegetarianMenu() {
// Iterator iterator = new CompositeIterator(allMenus.createIterator()); // Can't supply only allMenus.createIterator() even though that is what the instruction suggested
Iterator iterator = new CompositeIterator(null, allMenus.createIterator());
// Iterator iterator = allMenus.createIterator(); // print no vegetarian menus at all.

System.out.println("\nVEGETARIAN MENU\n----");
while (iterator.hasNext()) {
MenuComponent menuComponent =
(MenuComponent)iterator.next();
try {
if (menuComponent.isVegetarian()) {
menuComponent.print();
}
} catch (UnsupportedOperationException e) {}
}
}
}
--------------------------------------------------------------------------------------------
public class MenuTestDrive {
public static void main(String args[]) {

MenuComponent pancakeHouseMenu =
new Menu("PANCAKE HOUSE MENU", "Breakfast");
MenuComponent dinerMenu =
new Menu("DINER MENU", "Lunch");
MenuComponent cafeMenu =
new Menu("CAFE MENU", "Dinner");
MenuComponent dessertMenu =
new Menu("DESSERT MENU", "Dessert of course!");

MenuComponent allMenus = new Menu("ALL MENUS", "All menus combined");

allMenus.add(pancakeHouseMenu);
allMenus.add(dinerMenu);
allMenus.add(cafeMenu);

pancakeHouseMenu.add(new MenuItem(
"K&B's Pancake Breakfast",
"Pancakes with scrambled eggs, and toast",
true,
2.99));
pancakeHouseMenu.add(new MenuItem(
"Regular Pancake Breakfast",
"Pancakes with fried eggs, sausage",
false,
2.99));
pancakeHouseMenu.add(new MenuItem(
"Blueberry Pancakes",
"Pancakes made with fresh blueberries, and blueberry syrup",
true,
3.49));
pancakeHouseMenu.add(new MenuItem(
"Waffles",
"Waffles, with your choice of blueberries or strawberries",
true,
3.59));

dinerMenu.add(new MenuItem(
"Vegetarian BLT",
"(Fakin') Bacon with lettuce & tomato on whole wheat",
true,
2.99));
dinerMenu.add(new MenuItem(
"BLT",
"Bacon with lettuce & tomato on whole wheat",
false,
2.99));
dinerMenu.add(new MenuItem(
"Soup of the day",
"A bowl of the soup of the day, with a side of potato salad",
false,
3.29));
dinerMenu.add(new MenuItem(
"Hotdog",
"A hot dog, with saurkraut, relish, onions, topped with cheese",
false,
3.05));
dinerMenu.add(new MenuItem(
"Steamed Veggies and Brown Rice",
"A medly of steamed vegetables over brown rice",
true,
3.99));

dinerMenu.add(new MenuItem(
"Pasta",
"Spaghetti with Marinara Sauce, and a slice of sourdough bread",
true,
3.89));

dinerMenu.add(dessertMenu);

dessertMenu.add(new MenuItem(
"Apple Pie",
"Apple pie with a flakey crust, topped with vanilla icecream",
true,
1.59));
dessertMenu.add(new MenuItem(
"Cheesecake",
"Creamy New York cheesecake, with a chocolate graham crust",
true,
1.99));
dessertMenu.add(new MenuItem(
"Sorbet",
"A scoop of raspberry and a scoop of lime",
true,
1.89));

cafeMenu.add(new MenuItem(
"Veggie Burger and Air Fries",
"Veggie burger on a whole wheat bun, lettuce, tomato, and fries",
true,
3.99));
cafeMenu.add(new MenuItem(
"Soup of the day",
"A cup of the soup of the day, with a side salad",
false,
3.69));
cafeMenu.add(new MenuItem(
"Burrito",
"A large burrito, with whole pinto beans, salsa, guacamole",
true,
4.29));

Waitress waitress = new Waitress(allMenus);

waitress.printMenu();
waitress.printVegetarianMenu();
}
}[/code]
I am hoping to apply the same mechanism to building a FamilyTree application ([url]http://forums.sun.com/thread.jspa?threadID=5391569[/url]) which is encountering similar issue using the original incorrect approach used in the book.

Many thanks,

Jack
Jack Bush
Ranch Hand

Joined: Oct 20, 2006
Posts: 235
Hi,

It is not possible to pass only allMenus.createIterator() to a new instance of CompositeIterator in printVegetarianMenu because there no constructor or method that will take an Iterator as a parameter.

Any suggestion on what the parameter should be then?

Thanks,

Jack
Jack Bush
Ranch Hand

Joined: Oct 20, 2006
Posts: 235
Hi All,

Below is a correction to my implementation of the changes suggested in step 5 of (http://www.coderanch.com/t/100049/OO-Patterns-UML-Refactoring/Head-First-Design-Patterns-Composite):

[code]public class Waitress {
MenuComponent allMenus;

public Waitress(MenuComponent allMenus) {
this.allMenus = allMenus;
}

public void printMenu() {
// allMenus.print();
// Iterator iterator = new CompositeIterator(allMenus.createIterator()); // no constructor that will take an Iterator as a parameter in CompositeIterator.
Iterator iterator = allMenus.createIterator();
while (iterator.hasNext()) {
MenuComponent menuComponent = (MenuComponent)iterator.next();
menuComponent.print();
}
}

public void printVegetarianMenu() {
Iterator iterator = allMenus.createIterator();

System.out.println("\nVEGETARIAN MENU\n----");
while (iterator.hasNext()) {
MenuComponent menuComponent = (MenuComponent)iterator.next();
try {
if (menuComponent.isVegetarian()) {
menuComponent.print();
}
} catch (UnsupportedOperationException e) {}
}
}
}[/code]
Output generated from this change:
ALL MENUS, All menus combined
-------------------------------------

VEGETARIAN MENU
-------------------------------
 
GeeCON Prague 2014
 
subject: Couldn't get Menu Composite Iterator (HeadFirst Design Pattern) to work