意图:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表现。
结构:
让我们看一下一个例子:
对乡村的餐厅和对象村的煎饼屋合并了。现在碰到一个棘手的问题,餐厅的菜单是使用Arraylist来实现,而煎饼屋的菜单是用数组来进行实现的,由于各自的菜单已经与其他过多的代码进行耦合,所以不能进行更改,现在有一个女Waitress,需要打印全部菜单,我们最初设想就是去分别遍历各自的菜单,但是如果添加以后我们需要第三种遍历方式。。
我们来看这样的缺点:
1.重复代码过多,都是过多的循环遍历,虽然每种遍历方式不同。
2.将菜单的实现暴露在外,耦合过高。
现在我们来看,按照上述结构我们画出的类图如下:
下面我们具体看一下代码,煎饼屋的代码:
首先是Inteactor接口我们使用java的api自带的:
然后我们来看煎饼屋的午餐迭代器的实现:
import java.util.Iterator;
public class DinerMenuIterator implements Iterator {
MenuItem[] list;
int position = 0;
public DinerMenuIterator(MenuItem[] list) {
this.list = list;
}
public Object next() {
MenuItem menuItem = list[position];
position = position + 1;
return menuItem;
}
public boolean hasNext() {
if (position >= list.length || list[position] == null) {
return false;
} else {
return true;
}
}
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;
}
}
}
其中我们有一个menu的接口用于创建iterator:
public interface Menu {
public Iterator createIterator();
}
接着我们看午餐的菜单是如何实现的:
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);
addItem("Hotdog",
"A hot dog, with saurkraut, relish, onions, topped with cheese",
false, 3.05);
addItem("Steamed Veggies and Brown Rice",
"Steamed vegetables over brown rice", true, 3.99);
addItem("Pasta",
"Spaghetti with Marinara Sauce, and a slice of sourdough bread",
true, 3.89);
}
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;
}
public Iterator createIterator() {
return new DinerMenuIterator(menuItems);
}
// other menu methods here
}
最后我们来看客户,也就是我们的女招待员是如何驱使这些菜单的:
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() + ", ");
System.out.print(menuItem.getPrice() + " -- ");
System.out.println(menuItem.getDescription());
}
}
public void printVegetarianMenu() {
System.out.println("\nVEGETARIAN MENU\n----\nBREAKFAST");
printVegetarianMenu(pancakeHouseMenu.createIterator());
System.out.println("\nLUNCH");
printVegetarianMenu(dinerMenu.createIterator());
}
public boolean isItemVegetarian(String name) {
Iterator pancakeIterator = pancakeHouseMenu.createIterator();
if (isVegetarian(name, pancakeIterator)) {
return true;
}
Iterator dinerIterator = dinerMenu.createIterator();
if (isVegetarian(name, dinerIterator)) {
return true;
}
return false;
}
private void printVegetarianMenu(Iterator iterator) {
while (iterator.hasNext()) {
MenuItem menuItem = (MenuItem)iterator.next();
if (menuItem.isVegetarian()) {
System.out.print(menuItem.getName());
System.out.println("\t\t" + menuItem.getPrice());
System.out.println("\t" + menuItem.getDescription());
}
}
}
private boolean isVegetarian(String name, Iterator iterator) {
while (iterator.hasNext()) {
MenuItem menuItem = (MenuItem)iterator.next();
if (menuItem.getName().equals(name)) {
if (menuItem.isVegetarian()) {
return true;
}
}
}
return false;
}
}
这个就是我们客户的代码。
总结:
1.迭代器允许访问聚合元素,而不需要暴露它的内部结构。
2.迭代器将遍历聚合的工总封装到进另一个对象。
3.当使用迭代器的时候,我们依赖聚合提供遍历。