动机
一个聚合对象,应该提供一种方法来让别人可以访问它的元素,而又不需暴露它的内部结构. 此外,针对不同的需要,可能要以不同的方式遍历这个列表。
这一模式的关键思想是将对聚合对象的访问和遍历从聚合对象中分离出来并放入一个迭代器(iterator)对象中。
聚合对象:
聚合对象是一个管理和组织数据对象的数据结构,比如:Java中的list、map。
聚合对象拥有两个职责:
一是存储数据:是聚合对象的基本职责;
二是遍历数据:既是可变化的,又是可分离的。
意图
迭代器模式提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象内部表示.
别名:
游标(Cursor)
类型:
对象行为型模式
创建型模式:
将创建对象的过程进行了抽象
结构型模式:
怎样组装现有的类,设计他们的交互方式
行为型模式:
在不同对象之间划分职责和算法的抽象,行为模式不仅涉及到类和对象,还涉及到类与对象之间如何进行关联。
类行为型模式:使用继承机制在类间分派行为
对象行为型模式:使用对象组合的方式来完成行为的分派
多态迭代
适用性
1.访问一个聚合对象的内容而无须暴露它的内部表示。
2.需要为聚合对象提供多种遍历方式。
3.为遍历不同的聚合结构提供一个统一的接口。(多态迭代)
public interface Menu {
void addItem(int channel,String name,String description);
Iterator createIterator();
MenuItem get(int index);
int size();
}
public class MenuItem {
private int channel;//频道
private String name;//名字
private String description;//描述
public MenuItem(int channel, String name, String description) {
this.channel = channel;
this.name = name;
this.description = description;
}
public int getChannel() {
return channel;
}
public void setChannel(int channel) {
this.channel = channel;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public interface Iterator {
MenuItem currentItem();
void first();
boolean isDone();
void next();
}
public class FilmMenu implements Menu {
static final int MAX_SIZE=5;
private MenuItem[] menuItemArray;
public FilmMenu() {
menuItemArray =new MenuItem[MAX_SIZE];
addItem(1,"绝世天劫","这是布鲁斯威利斯主演的...");
addItem(2,"达芬奇密码","这是我最喜欢的电影之一...");
addItem(3,"黑客帝国123","不知道你能够看懂不???");
addItem(4,"我的女友是机器人","一部经典爱情电影");
addItem(5,"肖申克的救赎","自由,幸福,离你有多远");
}
@Override
public void addItem(int channel, String name, String description) {
MenuItem menuItem=new MenuItem(channel,name,description);
try {
menuItemArray[channel-1]=menuItem;
}catch (Exception e){
System.out.println("不好意思,菜单满了....");
}
}
@Override
public Iterator createIterator() {
return new FilmMenuIterator(this);
}
@Override
public MenuItem get(int index) {
if (index<MAX_SIZE){
return menuItemArray[index];
}
return null;
}
@Override
public int size() {
return MAX_SIZE;
}
}
public class FilmMenuIterator implements Iterator {
private FilmMenu filmMenu;
private int index;
public FilmMenuIterator(FilmMenu filmMenu) {
this.filmMenu = filmMenu;
this.index=-1;
}
@Override
public MenuItem currentItem() {
return filmMenu.get(index);
}
@Override
public void first() {
index=0;
}
@Override
public boolean isDone() {
if(index==filmMenu.size()){
return true;
}
return false;
}
@Override
public void next() {
if (index<filmMenu.size()){
index=index+1;
}
}
}
import java.util.ArrayList;
/**
* Created by yangy on 2017/6/22.
*/
public class TVChannelMenu implements Menu {
private ArrayList<MenuItem> menuItemList;
public TVChannelMenu(){
menuItemList=new ArrayList<MenuItem>();
addItem(1,"CCTV-1","This is CCTV-1");
addItem(2,"CCTV-2","This is CCTV-2");
addItem(3,"CCTV-3","This is CCTV-3");
addItem(4,"CCTV-4","This is CCTV-4");
addItem(5,"CCTV-5","This is CCTV-5");
}
@Override
public void addItem(int channel, String name, String description) {
MenuItem menuItem=new MenuItem(channel,name,description);
menuItemList.add(menuItem);
}
@Override
public Iterator createIterator() {
return new TVChannelMenuIterator(this);
}
@Override
public MenuItem get(int index) {
return menuItemList.get(index);
}
@Override
public int size() {
return menuItemList.size();
}
}
public class TVChannelMenuIterator implements Iterator {
private int index;
private TVChannelMenu tvChannelMenu;
public TVChannelMenuIterator(TVChannelMenu tvChannelMenu) {
this.tvChannelMenu = tvChannelMenu;
index=-1;
}
@Override
public MenuItem currentItem() {
return tvChannelMenu.get(index);
}
@Override
public void first() {
index=0;
}
@Override
public boolean isDone() {
if(index==tvChannelMenu.size()){
return true;
}
return false;
}
@Override
public void next() {
if(index<tvChannelMenu.size()){
index++;
}
}
}
public class Client {
public static void main(String[] args) {
Menu filmMenu=new FilmMenu();
Menu tvChannelMenu=new TVChannelMenu();
System.out.println("电影有:");
print(filmMenu.createIterator());
System.out.println("电视有:");
print(tvChannelMenu.createIterator());
}
private static void print(Iterator iterator){
iterator.first();
while (!iterator.isDone()){
MenuItem menuItem=iterator.currentItem();
System.out.print("channel:"+menuItem.getChannel()+", ");
System.out.print("name:"+menuItem.getName()+", ");
System.out.println("description:"+menuItem.getDescription());
iterator.next();
}
}
}
运行结果:
电影有:
channel:1, name:绝世天劫, description:这是布鲁斯威利斯主演的...
channel:2, name:达芬奇密码, description:这是我最喜欢的电影之一...
channel:3, name:黑客帝国123, description:不知道你能够看懂不???
channel:4, name:我的女友是机器人, description:一部经典爱情电影
channel:5, name:肖申克的救赎, description:自由,幸福,离你有多远
电视有:
channel:1, name:CCTV-1, description:This is CCTV-1
channel:2, name:CCTV-2, description:This is CCTV-2
channel:3, name:CCTV-3, description:This is CCTV-3
channel:4, name:CCTV-4, description:This is CCTV-4
channel:5, name:CCTV-5, description:This is CCTV-5
迭代器模式的优点和缺点
迭代器模式的优点:
(1)迭代器模式简化了聚合的界面。迭代器具备了一个遍历接口,这样聚合的接口就不必具备遍历接口。
(2)即使聚合对象的类型发生变化,也不会影响到客户端的遍历过程。由于遍历算法被封装在迭代器里面,因此迭代的算法可以独立于聚合角色变化。而客户端拿到的是一个迭代器对象。
迭代器模式的缺点:
(1)迭代器模式给客户端一个聚合对象被顺序化的错觉。因为大多数的情况下聚合对象的元素并没有确定的顺序,但是迭代器必须以一定线性顺序进行。
(2)迭代器模式在增加新的聚合类时,需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性
相关应用
JDK 1.2 引入了新的Java聚合框架Collection。
Collection的iterator()方法返回一个java.util.Iterator类型的对象,而其子接口java.util.List的listIterator()方法返回一个java.util.ListIterator类型的对象,ListIterator是Iterator的子类。它们构成了Java语言对迭代器模式的支持,Java语言的java.util.Iterator接口就是迭代器模式的应用。
模式扩展
Java迭代器
在JDK中,Iterator接口具有如下3个基本方法:
(1) Object next():通过反复调用next()方法可以逐个访问聚合对象中的元素。
(2) boolean hasNext():hasNext()方法用于判断聚合对象中是否还存在下一个元素。如果迭代对象仍然拥有可供访问的元素,那么hasNext()返回true。
(3) void remove():用于删除上次调用next()时所返回的元素。
Java迭代器可以理解为它工作在聚合对象的各个元素之间,每调用一次next()方法,迭代器便越过下个元素,并且返回它刚越过的那个元素的地址引用。
迭代器模式与工厂方法模式的关系
创建迭代器是一个Factory Method模式的例子。我们在这里用它来使得一个客户可向一个聚合对象请求合适的迭代器。Factory Method模式产生两个类层次,一个是聚合对象的,一个是迭代器的。CreateIterator”联系”这两个类层次。
多态迭代器靠Factory Method来实例化适当的迭代器子类。
迭代器模式与组合模式的关系
迭代器模式常常用来遍历一个按照组合模式建立起来的树结构。