概念参考:http://www.runoob.com/design-pattern/iterator-pattern.html
迭代器模式
迭代器模式(Iterator Pattern)是 Java 和 .Net 编程环境中非常常用的设计模式。这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。迭代器模式属于行为型模式。
介绍
意图:提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。
主要解决:不同的方式来遍历整个整合对象。
何时使用:遍历一个聚合对象。
如何解决:把在元素之间游走的责任交给迭代器,而不是聚合对象。
关键代码:定义接口:hasNext, next。
应用实例:JAVA 中的 iterator。
优点: 1、它支持以不同的方式遍历一个聚合对象。 2、迭代器简化了聚合类。 3、在同一个聚合上可以有多个遍历。 4、在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码。
缺点:由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。
使用场景: 1、访问一个聚合对象的内容而无须暴露它的内部表示。 2、需要为聚合对象提供多种遍历方式。 3、为遍历不同的聚合结构提供一个统一的接口。
注意事项:迭代器模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明地访问集合内部的数据。
实现
我们将创建一个叙述导航方法的 Iterator 接口和一个返回迭代器的 Container 接口。实现了 Container 接口的实体类将负责实现 Iterator 接口。
IteratorPatternDemo,我们的演示类使用实体类 NamesRepository 来打印 NamesRepository 中存储为集合的 Names。
步骤 1
创建接口:
Iterator.java //iterator必须有响应遍历方法并且能够拥有聚合对象
public interface Iterator {
public boolean hasNext();
public Object next();
}
Container.java //聚合对象必须能过获取到iterator对象
public interface Container {
public Iterator getIterator();
}
步骤 2
创建实现了 Container 接口的实体类。该类有实现了 Iterator 接口的内部类 NameIterator。
NameRepository.java
public class NameRepository implements Container {
public String names[] = {"Robert" , "John" ,"Julie" , "Lora"};
@Override
public Iterator getIterator() {
return new NameIterator();
}
//使用内部类方法包含iterator对象,而聚合对象又可以访问聚合对象的内容
private class NameIterator implements Iterator {
int index;
@Override
public boolean hasNext() {
if(index < names.length){
return true;
}
return false;
}
@Override
public Object next() {
if(this.hasNext()){
return names[index++];
}
return null;
}
}
}
步骤 3
使用 NameRepository 来获取迭代器,并打印名字。
IteratorPatternDemo.java
public class IteratorPatternDemo {
public static void main(String[] args) {
NameRepository namesRepository = new NameRepository();
for(Iterator iter = namesRepository.getIterator(); iter.hasNext();){
String name = (String)iter.next();
System.out.println("Name : " + name);
}
}
}
步骤 4
执行程序,输出结果:
Name : Robert
Name : John
Name : Julie
Name : Lora
实例二:
Aggregate.java //聚合抽象类
/**
* 聚合对象的接口,定义创建相应迭代器对象的接口
*/
public abstract class Aggregate {
/**
* 工厂方法,创建相应迭代器对象的接口
* @return 相应迭代器对象的接口
*/
public abstract Iterator createIterator();
}
ConcreteAggregate.java //聚合实现类: //通过创建对象方式返回遍历对象,但是自己必须将应用给遍历对象,这是一种推的方式
/**
* 具体的聚合对象,实现创建相应迭代器对象的功能
*/
public class ConcreteAggregate extends Aggregate {
/**
* 示意,表示聚合对象具体的内容
*/
private String[] ss = null;
/**
* 构造方法,传入聚合对象具体的内容
* @param ss 聚合对象具体的内容
*/
public ConcreteAggregate(String[] ss){
this.ss = ss;
}
//通过创建对象方式返回遍历对象,但是自己必须将应用给遍历对象,这是一种推的方式
public Iterator createIterator() {
//实现创建Iterator的工厂方法
return new ConcreteIterator(this);
}
/**
* 获取索引所对应的元素
* @param index 索引
* @return 索引所对应的元素
*/
public Object get(int index){
Object retObj = null;
if(index < ss.length){
retObj = ss[index];
}
return retObj;
}
/**
* 获取聚合对象的大小
* @return 聚合对象的大小
*/
public int size(){
return this.ss.length;
}
}
Iterator.java //迭代接口:定义遍历方法
/**
* 迭代器接口,定义访问和遍历元素的操作
*/
public interface Iterator {
/**
* 移动到聚合对象的第一个位置
*/
public void first();
/**
* 移动到聚合对象的下一个位置
*/
public void next();
/**
* 判断是否已经移动聚合对象的最后一个位置
* @return true表示已经移动到聚合对象的最后一个位置,
* false表示还没有移动到聚合对象的最后一个位置
*/
public boolean isDone();
/**
* 获取迭代的当前元素
* @return 迭代的当前元素
*/
public Object currentItem();
}
ConcreteIterator.java //具体迭代实现:必须获取到聚合对象的引用
/**
* 具体迭代器实现对象,示意的是聚合对象为数组的迭代器
* 不同的聚合对象相应的迭代器实现是不一样的
*/
public class ConcreteIterator implements Iterator {
/**
* 持有被迭代的具体的聚合对象
*/
private ConcreteAggregate aggregate;
/**
* 内部索引,记录当前迭代到的索引位置。
* -1表示刚开始的时候,迭代器指向聚合对象第一个对象之前
*/
private int index = -1;
/**
* 构造方法,传入被迭代的具体的聚合对象
* @param aggregate 被迭代的具体的聚合对象
*/
//通过构造器获取到引用
public ConcreteIterator(ConcreteAggregate aggregate) {
this.aggregate = aggregate;
}
public void first(){
index = 0;
}
public void next(){
if(index < this.aggregate.size()){
index = index + 1;
}
}
public boolean isDone(){
if(index == this.aggregate.size()){
return true;
}
return false;
}
public Object currentItem(){
return this.aggregate.get(index);
}
}
Client.java //遍历对象
public class Client {
/**
* 示意方法,使用迭代器的功能。
* 这里示意使用迭代器来迭代聚合对象
*/
public void someOperation(){
String[] names = {"张三","李四","王五"};
//创建聚合对象
Aggregate aggregate = new ConcreteAggregate(names);
//循环输出聚合对象中的值
Iterator it = aggregate.createIterator();
//首先设置迭代器到第一个元素
it.first();
while(!it.isDone()){
//取出当前的元素来
Object obj = it.currentItem();
System.out.println("the obj=="+obj);
//如果还没有迭代到最后,那么就向下迭代一个
it.next();
}
}
public static void main(String[] args) {
//可以简单的测试一下
Client client = new Client();
client.someOperation();
}
}
总结:迭代器主要两个部分,一个是迭代对象和聚合类,使用面向接口方式往往就是4个class,迭代器只要是定义遍历方法和实现这些方法,聚合对象主要是提供需要遍历的元素.那么这两个对象为什么必须相互持有引用呢?迭代器需要使用聚合方式获取聚合对象很正常,因为需要遍历该对象就必须拥有元素以及集合大小;而聚合对象持有遍历对象就是为了是客户端在使用时候不需要自己创建遍历对象然后去组合他们的关系来实现遍历功能,这样方式更具有封装性,更加面向对象,用户只需要创建必须要创建的聚合对象即可,然后调用方法就可以创建遍历对象,这样更加简单,也符合面向对象思想