定義
迭代器模式(iterator pattern)提供了一種方法順序訪問一個集合對象中的各個元素,而又不暴露其內部的表示。
代碼實現
下面以JDK現有的Iterator的例子來說明適配器模式使用。
給出創建Iterator接口的定義:
import java.util.Iterator;
public interface Menu {
public Iterator createIterator();
}
菜單項的BEAN對象:
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;
}
}
具體集合對象,管理(增加,移除,查找等)集合的元素,實現創建Iterator接口
import java.util.ArrayList;
import java.util.Iterator;
public class PancakeHouseMenu implements Menu {
// 內部存儲是ArrayList
ArrayList menuItems;
public PancakeHouseMenu() {
menuItems = new ArrayList();
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);
addItem("Blueberry Pancakes",
"Pancakes made with fresh blueberries, and blueberry syrup",
true,
3.49);
addItem("Waffles",
"Waffles, with your choice of blueberries or strawberries",
true,
3.59);
}
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;
}
public Iterator createIterator() {
return menuItems.iterator();
}
// other menu methods here
}
另一個具體集合對象,內部的存儲是數組
import java.util.Iterator;
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",
"A medly of 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; // 使用JDK中迭代器接口
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;
}
}
}
另一個具體集合對象,內部的存儲是Hashtable
import java.util.*;
public class CafeMenu implements Menu {
Hashtable menuItems = new Hashtable(); //內部的存儲是Hashtable
public CafeMenu() {
addItem("Veggie Burger and Air Fries",
"Veggie burger on a whole wheat bun, lettuce, tomato, and fries",
true, 3.99);
addItem("Soup of the day",
"A cup of the soup of the day, with a side salad",
false, 3.69);
addItem("Burrito",
"A large burrito, with whole pinto beans, salsa, guacamole",
true, 4.29);
}
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 Hashtable getItems() {
return menuItems;
}
public Iterator createIterator() {
return menuItems.values().iterator();
}
}
客戶(招待員)代碼,她持有Menu接口,通過這個接口去創建迭代器遍歷菜單,她不需要知道菜單項內部的存儲細節。
import java.util.Iterator;
public class Waitress {
Menu pancakeHouseMenu; // 煎餅屋菜單
Menu dinerMenu; // 餐廳菜單
Menu cafeMenu; // 咖啡廳菜單
public Waitress(Menu pancakeHouseMenu, Menu dinerMenu, Menu cafeMenu) {
this.pancakeHouseMenu = pancakeHouseMenu;
this.dinerMenu = dinerMenu;
this.cafeMenu = cafeMenu;
}
public void printMenu() {
// 生成迭代器接口
Iterator pancakeIterator = pancakeHouseMenu.createIterator();
Iterator dinerIterator = dinerMenu.createIterator();
Iterator cafeIterator = cafeMenu.createIterator();
System.out.println("MENU\n----\nBREAKFAST");
printMenu(pancakeIterator);
System.out.println("\nLUNCH");
printMenu(dinerIterator);
System.out.println("\nDINNER");
printMenu(cafeIterator);
}
// 遍歷迭代器,遍歷所有迭代器的代碼都可以複用這段代碼
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---------------");
printVegetarianMenu(pancakeHouseMenu.createIterator());
printVegetarianMenu(dinerMenu.createIterator());
printVegetarianMenu(cafeMenu.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;
}
Iterator cafeIterator = cafeMenu.createIterator();
if (isVegetarian(name, cafeIterator)) {
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.print(menuItem.getPrice() + " -- ");
System.out.println(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;
}
}
測試驅動代碼
import java.util.*;
public class MenuTestDrive {
public static void main(String args[]) {
//
Menu pancakeHouseMenu = new PancakeHouseMenu();
Menu dinerMenu = new DinerMenu();
Menu cafeMenu = new CafeMenu();
Waitress waitress = new Waitress(pancakeHouseMenu, dinerMenu, cafeMenu);
// 各種遍歷菜單的方式
waitress.printMenu();
waitress.printVegetarianMenu();
System.out.println("\nCustomer asks, is the Hotdog vegetarian?");
System.out.print("Waitress says: ");
if (waitress.isItemVegetarian("Hotdog")) {
System.out.println("Yes");
} else {
System.out.println("No");
}
System.out.println("\nCustomer asks, are the Waffles vegetarian?");
System.out.print("Waitress says: ");
if (waitress.isItemVegetarian("Waffles")) {
System.out.println("Yes");
} else {
System.out.println("No");
}
}
}
從上面的代碼可以看出,迭代器模式讓客戶遍歷集合的代碼更加通用,它不用關心集合內部的存儲細節,因爲集合對象創建的迭代器封裝了遍歷具體數據結構的細節。
該模式體現了哪些OO原則
原則1: 封裝變化原則
這裏變化的部分是,由不同的集合類型所造成的遍歷方式不同。所以需要把遍歷方式封裝起來。-
迭代器模式把遍歷集合內元素的操作交給了迭代器(或者迭代器的子類),而集合本身專注在管理元素,這符合單一責任原則,讓設計具有高內聚的特性。
本章總結
Java Collection框架裏面很多類都實現了Iterator接口,可細研究
集合類把遍歷集合內元素的責任封裝在Iterator接口,集合只需要專注在管理集合的元素,比如,添加,刪除,查找等。讓一個類只做一件事,遵守單一責任原則,這樣的設計更加容易維護