一、迭代器模式概述
迭代器模式定义:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。把游走的任务放在送代器上,而不是聚合上。这样简化了聚含的接口和实现,也让责任各得其所。(对象行为型)
-
迭代器模式的优缺点 :
- 优点 :
- 1.访问一个聚合对象的内容而无须暴露它的内部表示;
- 2.遍历任务交由迭代器完成,这简化了聚合类;
- 3.它支持以不同方式遍历一个聚合,甚至可以自定义迭代器的子类以支持新的遍历;
- 4.增加新的聚合类和迭代器类都很方便,无须修改原有代码;
- 5.封装性良好,为遍历不同的聚合结构提供一个统一的接口;
- 缺点 :
- 增加了类的个数,这在一定程度上增加了系统的复杂性。
- 优点 :
-
适用环境 :
- 内容保密 : 访问集合对象的内容 , 无需暴露内部表示 ;
- 统一接口 : 为遍历不同的集合结构 , 提供统一接口。
二、代码实现
迭代器模式主要包含四个角色:
- **抽象聚合(Aggregate)**角色:定义存储、添加、删除聚合对象以及创建迭代器对象的接口。
- **具体聚合(ConcreteAggregate)**角色:实现抽象聚合类,返回一个具体迭代器的实例。
- **抽象迭代器(Iterator)**角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、first()、next() 等方法。
- **具体迭代器(Concretelterator)**角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。
2.1 抽象聚合(MenuItem)
java
package iterator.Menu;
//抽象聚合角色
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;
}
}
2.2 具体聚合(DinnerMenu)
java
package iterator.Menu;
//菜单类
public class DinnerMenu {
// 菜单总数
private final static int MAX_NUMBER_OF_ITEMS = 4;
private MenuItem[] menuItems;
// 菜单量
private int numberOfItems = 0;
// 初始化数组,添加菜单内容
public DinnerMenu() {
menuItems = new MenuItem[MAX_NUMBER_OF_ITEMS];
addItem("pancake1", "good1", true, 10.5);
addItem("pancake2", "good2", false, 11.5);
addItem("pancake3", "good3", true, 12.5);
addItem("pancake4", "good4", false, 13.5);
}
// 创建一个添加菜单方法
public void addItem(String name, String description, boolean vegetarian, double prive) {
MenuItem menuItem = new MenuItem(name, description, vegetarian, prive);
if (numberOfItems >= MAX_NUMBER_OF_ITEMS) {
throw new RuntimeException("超过最大数量");
} else {
//菜单没满可以继续添加
menuItems[numberOfItems] = menuItem;
numberOfItems++;
}
}
// 使用迭代器遍历菜单
public Iterator createIterator() {
return new DinnerMenuIterator(this.menuItems);
}
//..其他方法
}
2.3 抽象迭代器
java
package iterator.Menu;
//抽象迭代器
public interface Iterator {
// hasNext()方法返回一个布尔值,让我们知道是否还有更多的元素
boolean hasNext();
// next()方法返回下一个元素
Object next();
}
2.4 具体迭代器(DinnerMenuIterator)
java
package iterator.Menu;
//具体迭代器,餐厅菜单
public class DinnerMenuIterator implements Iterator {
MenuItem[] items;
// iteratorIndex记录当前数组遍历的位置
int iteratorIndex = 0;;
// 构造器需要被传入一个菜单项的数组当做参数
public DinnerMenuIterator(MenuItem[] items) {
this.items = items;
}
// next()方法返回数组内的下一项,并递增其位置
public Object next() {
MenuItem menuItem = items[iteratorIndex];
iteratorIndex = iteratorIndex + 1;
return menuItem;
}
// hasNext()方法会检查我们是否已经取得数组内所有的元素。
// 如果还有元素待遍历,则返回true
public boolean hasNext() {
if (iteratorIndex >= items.length || items[iteratorIndex] == null) {
return false;
} else {
return true;
}
}
}
2.5 服务员(Waitress)
java
package iterator.Menu;
//服务员
public class Waitress {
PancakeHouseMenu pancakeHouseMenu;
DinnerMenu dinnerMenu;
// 在构造器中,女招待照顾两个菜单
public Waitress(PancakeHouseMenu pancakeHouseMenu, DinnerMenu dinnerMenu) {
this.pancakeHouseMenu = pancakeHouseMenu;
this.dinnerMenu = dinnerMenu;
}
public void printMenu() {
// 这个printMenu()方法为每一个菜单各自创建一个迭代器
Iterator pancakeIterator = pancakeHouseMenu.createIterator();
Iterator dinnerIterator = dinnerMenu.createIterator();
// 然后调用重载的printMenu(),将迭代器传入
printMenu(pancakeIterator);
System.out.println("\nLunch");
// 调用下面重载的方法
printMenu(dinnerIterator);
}
// 这个重载的printMenu()方法,使用迭代器来遍历菜单项并打印出来
// 使用迭代器(一次循环即可)来遍历菜单项并打印出来,只调用Iterator接口
private void printMenu(Iterator iterator) {
while (iterator.hasNext()) {
MenuItem menuItem = (MenuItem) iterator.next();
System.out.println(menuItem.getName() + " " +
menuItem.getPrice() + " " + menuItem.getDescription());
}
}
}
2.6 main方法实现迭代器(Test)
java
package iterator.Menu;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();
DinnerMenu dineMenu = new DinnerMenu();
/**
*两个菜单都实现一样的方法,但是并没有实现相同的接口,
*女招待还是要依赖两个具体实现的菜单类
*后面就要修改这里
*
*/
Waitress waitress = new Waitress(pancakeHouseMenu, dineMenu);
waitress.printMenu();
}
}