您的位置:首页 > 其它

《HeadFirst设计模式》读书笔记-第9章-迭代器模式

2017-04-24 08:26 295 查看

定义

迭代器模式(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 menuItems; // 内部存储是ArrayList

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");
}
}
}


从上面的代码可以看出,迭代器让客户遍历集合的代码更加通用,它不用关心集合内部的存储细节,因为集合对象创建的迭代器封装了遍历具体数据结构的细节。

本章金句

Java Collection框架里面很多类都实现了Iterator接口,可细研究

集合类把遍历集合内元素的责任封装在Iterator接口,集合只需要专注在管理集合的元素,比如,添加,删除,查找等。让一个类只做一件事,遵守单一责任原则,这样的设计更加容易维护
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息