迭代器模式(Iterator Pattern)是 Java 和 .Net 编程环境中非常常用的设计模式。这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。
迭代器模式属于行为型模式。
介绍
意图:提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。
主要解决:不同的方式来遍历整个整合对象。
何时使用:遍历一个聚合对象。
如何解决:把在元素之间游走的责任交给迭代器,而不是聚合对象。
关键代码:定义接口:hasNext, next。
应用实例:JAVA 中的 iterator。
优点: 1、它支持以不同的方式遍历一个聚合对象。 2、迭代器简化了聚合类。 3、在同一个聚合上可以有多个遍历。 4、在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码。
缺点:由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。
使用场景: 1、访问一个聚合对象的内容而无须暴露它的内部表示。 2、需要为聚合对象提供多种遍历方式。 3、为遍历不同的聚合结构提供一个统一的接口。
注意事项:迭代器模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明地访问集合内部的数据。
demo
定义一个菜单项类,里面有菜单价格、名字、描述属性,
有两个餐厅DinerMenu和pancakeHourseMenu 它们可以添加菜单项,得到菜单集合
女服务员Waitress,负责根据不同的餐厅打印出他们的菜单集合
定义一个菜单接口
package menu;
import item.MenuItem;
public interface Menu
{
/**
* 添加菜单项
* @param name
* @param description
* @param price
*/
void addItem(String name, String description, double price);
/**
* 获取菜单项集合
*/
Object getMenuItems();
}
定义一个菜单项类
package item;
/**
* 菜单项
*/
public class MenuItem
{
private String name; //菜单项名称
private String description; //描述
private double price; //价格
public MenuItem(String name,
String description,
double price)
{
this.name = name;
this.description = description;
this.price = price;
}
public String toString()
{
return (name + ": "+description+", $" + price);
}
}
定义两个餐厅类,他们实现了菜单接口
package menu;
import item.MenuItem;
import java.util.ArrayList;
import java.util.Iterator;
/**
* 煎饼屋餐厅
*/
public class PancakeHouseMenu implements Menu
{
private ArrayList<MenuItem> menuItems;
public PancakeHouseMenu()
{
menuItems = new ArrayList();
addItem("薄煎饼早餐",
"薄煎饼、鸡蛋和土司",
2.99);
addItem("蓝莓薄煎饼",
"新鲜蓝莓和蓝莓果酱做成的薄煎饼",
2.99);
addItem("松饼",
"松饼,可以选择蓝莓或者草莓口味",
3.59);
}
public void addItem(String name, String description, double price)
{
MenuItem menuItem = new MenuItem(name, description, price);
menuItems.add(menuItem);
}
public ArrayList<MenuItem> getMenuItems()
{
return menuItems;
}
}
package menu;
import item.MenuItem;
import iterator.DinerMenuIterator;
import java.util.Iterator;
/**
* 对象村餐厅
*/
public class DinerMenu implements Menu
{
private static final int MAX_ITEMS = 4;
private int numberOfItems = 0;
private MenuItem[] menuItems;
public DinerMenu() {
menuItems = new MenuItem[MAX_ITEMS];
addItem("素食 BLT", "(煎)培根, 生菜和西红柿", 2.99);
addItem("清汤", "一碗清汤, 配土豆沙拉", 3.29);
addItem("热狗", "一个热狗, 酸菜, 芝士, 洋葱", 3.05);
addItem("清蒸时蔬加糙米", "清蒸的蔬菜配糙米", 3.99);
}
public void addItem(String name, String description, double price)
{
MenuItem menuItem = new MenuItem(name, description, price);
if (numberOfItems >= MAX_ITEMS)
{
System.err.println("抱歉, 菜单已满! 不能添加菜单项");
}
else
{
menuItems[numberOfItems] = menuItem;
numberOfItems = numberOfItems + 1;
}
}
public MenuItem[] getMenuItems()
{
return menuItems;
}
}
定义一个服务员,它可以根据餐厅名上菜单
import item.MenuItem;
import menu.DinerMenu;
import menu.PancakeHouseMenu;
import java.util.ArrayList;
/**
* 服务员类,根据餐厅打印菜单
*/
public class Waitress
{
private PancakeHouseMenu pancakeHouseMenu;
private DinerMenu dinerMenu;
public Waitress(PancakeHouseMenu pancakeHouseMenu, DinerMenu dinerMenu) {
this.pancakeHouseMenu = pancakeHouseMenu;
this.dinerMenu = dinerMenu;
}
/**
* 打印煎饼屋菜单
*/
public void printPancakeHouseMenu() {
ArrayList<MenuItem> pancakeHouseItems = pancakeHouseMenu.getMenuItems();
for (int i = 0; i < pancakeHouseItems.size(); i++)
{
MenuItem menuItem = pancakeHouseItems.get(i);
System.out.println(menuItem);
}
System.out.println("\n");
}
/**
* 打印餐厅村菜单
*/
public void printdinerMenu() {
MenuItem[] menuItems = dinerMenu.getMenuItems();
for (int i = 0; i < menuItems.length; i++)
{
MenuItem menuItem = menuItems[i];
System.out.println(menuItem);
}
System.out.println("\n");
}
}
测试类
import menu.DinerMenu;
import menu.PancakeHouseMenu;
public class Test
{
public static void main(String[] args)
{
PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();
DinerMenu dinerMenu = new DinerMenu();
Waitress waitress=new Waitress(pancakeHouseMenu,dinerMenu);
System.out.println("煎饼屋餐厅菜单------------------------");
waitress.printPancakeHouseMenu();
System.out.println("对象村餐厅菜单-------------------------");
waitress.printdinerMenu();
}
}
从以上例子可以看出,服务员中的打印菜单方法要遍历每个餐厅的菜单,非常麻烦,首先服务员的属性中必须是两个具体的餐厅类型,而且在遍历时由于每个餐厅里面的菜单项集合类型不同,则遍历时候的操作也不一样,如果再增加一个餐厅和它的菜单类型,则就需要第三种循环方法
思考:如果我们能找打一个方法,让每个餐厅的菜单项都实现一个相同的接口,而不改变菜单项的集合类型,这样就可以最小化招待员代码中的具体引用,同时还可以摆脱遍历这两个菜单所需的多个循环,让招待员和餐厅解耦,把集合的操作交给迭代器
首先上类图
步骤:我们先创建一个迭代器
package iterator;
import item.MenuItem;
/**
* 自定义一个迭代器接口
*/
public interface Iterator<E>
{
boolean hasNext();
MenuItem next();
}
现在我们需要为每个餐厅添加他们自己的迭代器
package iterator;
import item.MenuItem;
public class DinerMenuIterator implements Iterator
{
private MenuItem[] menuItems;
private int position = 0;
public DinerMenuIterator(MenuItem[] menuItems)
{
this.menuItems = menuItems;
}
@Override
public boolean hasNext()
{
if (position >= menuItems.length || menuItems[position] == null)
return false;
else
return true;
}
@Override
public MenuItem next()
{
MenuItem menuItem = menuItems[position++];
return menuItem;
}
}
package iterator;
import item.MenuItem;
import java.util.ArrayList;
public class PancakeHouseMenuIterator implements Iterator
{
ArrayList<MenuItem> items;
int position = 0;
public PancakeHouseMenuIterator(ArrayList<MenuItem> items)
{
this.items = items;
}
public MenuItem next()
{
MenuItem item = items.get(position);
position = position + 1;
return item;
}
public boolean hasNext()
{
if (position >= items.size())
return false;
else
return true;
}
}
接着在每个餐厅中增加一个createIterator()方法
package menu;
import item.MenuItem;
import iterator.PancakeHouseMenuIterator;
import java.util.ArrayList;
import iterator.Iterator;
/**
* 煎饼屋餐厅
*/
public class PancakeHouseMenu implements Menu
{
private ArrayList<MenuItem> menuItems;
public PancakeHouseMenu()
{
menuItems = new ArrayList();
addItem("薄煎饼早餐",
"薄煎饼、鸡蛋和土司",
2.99);
addItem("蓝莓薄煎饼",
"新鲜蓝莓和蓝莓果酱做成的薄煎饼",
2.99);
addItem("松饼",
"松饼,可以选择蓝莓或者草莓口味",
3.59);
}
public void addItem(String name, String description, double price)
{
MenuItem menuItem = new MenuItem(name, description, price);
menuItems.add(menuItem);
}
public ArrayList<MenuItem> getMenuItems()
{
return menuItems;
}
public Iterator<MenuItem> createIterator() {
return new PancakeHouseMenuIterator(menuItems);
}
}
package menu;
import item.MenuItem;
import iterator.DinerMenuIterator;
import iterator.Iterator;
/**
* 对象村餐厅
*/
public class DinerMenu implements Menu
{
private static final int MAX_ITEMS = 4;
private int numberOfItems = 0;
private MenuItem[] menuItems;
public DinerMenu() {
menuItems = new MenuItem[MAX_ITEMS];
addItem("素食 BLT", "(煎)培根, 生菜和西红柿", 2.99);
addItem("清汤", "一碗清汤, 配土豆沙拉", 3.29);
addItem("热狗", "一个热狗, 酸菜, 芝士, 洋葱", 3.05);
addItem("清蒸时蔬加糙米", "清蒸的蔬菜配糙米", 3.99);
}
public void addItem(String name, String description, double price)
{
MenuItem menuItem = new MenuItem(name, description, price);
if (numberOfItems >= MAX_ITEMS)
{
System.err.println("抱歉, 菜单已满! 不能添加菜单项");
}
else
{
menuItems[numberOfItems] = menuItem;
numberOfItems = numberOfItems + 1;
}
}
public MenuItem[] getMenuItems()
{
return menuItems;
}
@Override
public Iterator<MenuItem> createIterator() {
return new DinerMenuIterator(menuItems);
}
}
在次修改服务员类
import item.MenuItem;
import menu.DinerMenu;
import menu.PancakeHouseMenu;
import java.util.ArrayList;
import iterator.Iterator;
/**
* 服务员类,根据餐厅打印菜单
*/
public class Waitress
{
private PancakeHouseMenu pancakeHouseMenu;
private DinerMenu dinerMenu;
public Waitress(PancakeHouseMenu pancakeHouseMenu, DinerMenu dinerMenu) {
this.pancakeHouseMenu = pancakeHouseMenu;
this.dinerMenu = dinerMenu;
}
/**
* 打印煎饼屋菜单
*/
public void printPancakeHouseMenu() {
ArrayList<MenuItem> pancakeHouseItems = pancakeHouseMenu.getMenuItems();
for (int i = 0; i < pancakeHouseItems.size(); i++)
{
MenuItem menuItem = pancakeHouseItems.get(i);
System.out.println(menuItem);
}
System.out.println("\n");
}
/**
* 打印餐厅村菜单
*/
public void printdinerMenu() {
MenuItem[] menuItems = dinerMenu.getMenuItems();
for (int i = 0; i < menuItems.length; i++)
{
MenuItem menuItem = menuItems[i];
System.out.println(menuItem);
}
System.out.println("\n");
}
public void printMenu() {
Iterator pancakeIterator = pancakeHouseMenu.createIterator();
Iterator dinerIterator = dinerMenu.createIterator();
printMenu(pancakeIterator);
printMenu(dinerIterator);
}
private void printMenu(Iterator iterator) {
while (iterator.hasNext()) {
MenuItem menuItem = iterator.next();
System.out.println(menuItem);
}
}
}
最后的测试类
import menu.DinerMenu;
import menu.PancakeHouseMenu;
public class Test
{
public static void main(String[] args)
{
PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();
DinerMenu dinerMenu = new DinerMenu();
Waitress waitress=new Waitress(pancakeHouseMenu,dinerMenu);
waitress.printMenu();
}
}
运行 结果一样