设计模式之迭代子模式

迭代子模式又叫游标(Cursor)模式,是对象的行为模式。html

迭代子模式的定义

迭代子模式能够顺序地访问一个汇集中的元素而没必要暴露汇集的内部表象。咱们常见的集合有不少种类,其顶层数据存储和组织方式的不一样致使了咱们在对数据进行遍历的时候存在一些差别,迭代器模式就是经过实现某种统一的方式来实现对不一样的集合的遍历,同时又不暴露出其底层的数据存储和组织方式。java

例如,若是没有使用Iterator,遍历一个数组的方法是使用索引:设计模式

for(int i=0; i<array.size(); i++) { 
	get(i)
} 
复制代码

而访问一个链表(LinkedList)又必须使用while循环:数组

while((e=e.next())!=null) { 
	 e.data()
} 
复制代码

以上两种方法客户端都必须事先知道集合的内部结构,访问代码和集合自己是紧耦合,没法将访问逻辑从集合类和客户端代码中分离出来,每一种集合对应一种遍历方法,客户端代码没法复用。微信

更恐怖的是,若是之后须要把ArrayList更换为LinkedList,则原来的客户端代码必须所有重写。ide

为解决以上问题,Iterator模式老是用同一种逻辑来遍历集合:测试

for(Iterator it = yourCollection.iterater(); it.hasNext(); ) 
{ ... } 
复制代码

客户端自身不维护遍历集合的"指针",全部的内部状态(如当前元素位置,是否有下一个元素)都由Iterator来维护,而这个Iterator由集合类经过工厂方法生成,所以,它知道如何遍历整个集合。客户端从不直接和集合类打交道,它老是控制Iterator,向它发送"向前","向后","取当前元素"的命令,就能够间接遍历整个集合。this

迭代子模式的结构

迭代模式中有以下的角色: spa

iteratorconstruct
迭代子模式的结构

  • 迭代器角色(Iterator): 负责定义访问和遍历元素的接口。
  • 具体迭代器角色(Concrete Iterator):实现迭代器接口,并要记录遍历中的当前位置。
  • 容器角色(Container): 负责提供建立具体迭代器角色的接口。
  • 具体容器角色(Concrete Container):实现建立具体迭代器角色的接口, 这个具体迭代器角色与该容器的结构相关。

迭代子模式的实现

迭代器接口实现,定义了获取第一个节点的方法,前一个节点和后一个节点,以及判断是否有下一个节点。设计

public interface Iterator {
    public Object first();
    
    public Object previous();
    
    public Object next();

    public boolean hasNext();
}
复制代码

具体实现迭代器,实现上述接口定义的方法。

public class MyIterator implements Iterator{
    private List<Object> list;
    private int index = 0;

    public MyIterator(List<Object> list) {
        this.list = list;
    }
    @Override
    public Object previous() {
        if((this.index - 1) < 0){
            return null;
        }else{
            return this.list.get(--index);
        }
        
    }

    @Override
    public Object next() {
        if((this.index + 1) >= this.list.size()){
            return null;
        }else{
            return this.list.get(++index);
        }
    }
    @Override
    public boolean hasNext() {
        if(this.index < (this.list.size() - 1)){
            return true;
        }
        return false;
    }

    @Override
    public Object first() {
        if(this.list.size() <= 0){
            return null;
        }else{
            return this.list.get(0);
        }
    }
}
复制代码

容器定义,定义了两个抽象方法,用来设置具体的迭代器实现以及注入容器中的元素。

public abstract class Container {

    public abstract Iterator iterator();
    
    public abstract void put(Object obj);
}
复制代码

具体的容器类基于List,实现抽象方法。

public class MyContainer extends Container{
    private List<Object> list;
    
    public MyContainer() {
        this.list = new ArrayList<Object>();
    }
    @Override
    public void put(Object obj){
        this.list.add(obj);
    }
    @Override
    public Iterator iterator() {
        return new MyIterator(list);
    }
}
复制代码

客户端测试类。设置元素,并使用迭代器进行遍历。

public class ClientTest {

	public static void main(String[] args) {

		//建立一个自定义容器,直接使用ArrayList的实现
		Container strContainer = new MyContainer();
		strContainer.put("001");
		strContainer.put("002");

		Iterator myIterator = strContainer.iterator();

		//使用迭代器遍历
		System.out.println(myIterator.first());
		while (myIterator.hasNext()) {
			System.out.println(myIterator.next());
		}
	}
}
复制代码

iterator
类图

总结

Iterator模式是用于遍历集合类的标准访问方法。它能够把访问逻辑从不一样类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构。

适用场景:

  • 访问一个聚合对象的内容而无须暴露它的内部表示。
  • 须要为聚合对象提供多种遍历方式。
  • 为遍历不一样的聚合结构提供一个统一的接口。

优势:

  • 它支持以不一样的方式遍历一个聚合对象。
  • 迭代器简化了聚合类。在同一个聚合上能够有多个遍历。
  • 在迭代器模式中,增长新的聚合类和迭代器类都很方便,无须修改原有代码。
  • 系统须要访问一个聚合对象的内容而无需暴露它的内部表示。

缺点:

  • 因为迭代器模式将存储数据和遍历数据的职责分离,增长新的聚合类须要对应增长新的迭代器类,类的个数成对增长,这在必定程度上增长了系统的复杂性。
  • 迭代器模式在遍历的同时更改迭代器所在的集合结构会致使出现异常。因此使用foreach语句只能在对集合进行遍历,不能在遍历的同时更改集合中的元素。

订阅最新文章,欢迎关注个人公众号

微信公众号

参考

  1. java设计模式----迭代子模式
  2. Head First设计模式之迭代器模式
相关文章
相关标签/搜索