设计模式之迭代器(Iterator)模式

定义(是什么)

Iterator设计模式是GOF提出的23种设计模式之一,也被叫做迭代模式。
作用是:将容器中所包含的内部对象按照集合的顺序委托给外部类进行访问,是行为模式之一

两个步骤:

  1. 将需要遍历的集合委托出去
  2. 一个一个按顺序进行遍历
为什么要使用Iterator设计模式

使用设计模式主要是为了遵循程序开发的6大原则,增强代码的可维护性、可扩展性、可复用性和灵活性。所以可以假想一下,我们如果不是用Iterator迭代设计模式时会怎么做?
有两种可能:
1、在需要便利的类中进行遍历。来看这个例子

public class Book{
	......
}

public class BookList{

    private List<Book> bookList = new ArrayList<Book>();
    public void addBook(Book book){
		......
    }

    public void removeBook(Book book){
		......
    }

	public boolean hasNext(){
		......
	}

	public boolean next(){
		......
	}
    //在类中减需要遍历的一个一个取出
    public Book forEachBookListToOne(){
    	//实现遍历操作的代码
		......
    }
}

缺点:违反了程序设计的单一原则,既承担了对集合的增删的操作,又需要对集合进行遍历输出,耦合度太高。

2、将集合的数据细节暴露出去,给外部类进行遍历访问操作。

List<Book> list = new BookList().getBookList();
for(Book book : list){
	......
}

WARN:总结不使用Iterator模式的缺点
1. 容器类本身承担了太多的功能,既要添加删除、又要提供遍历访问
2. 容器类在遍历访问时往往需要保存遍历的状态,这样在删除或添加时,容器引起混乱和冲突

使用迭代器模式

Iterator模式类图

以上是Java中的Iterator模式的类图,

--------List接口(角色:Aggregate)---------

public interface List<E>  {
	......
	Iterator<E> iterator();
	......
}

此处只显示iterator迭代模式相关的代码,其余的接用省略符号替代

List接口中有一个iterator()方法持有一个Iterator迭代器的实例,想要遍历该元素的集合,可以调用该方法去得到这个迭代器。

--------ArrayList接口(角色:ConcreteAggregate)---------

public class ArrayList<E> {
	......
	public Iterator<E> iterator() {
        return new Itr();
    }
    private class Itr implements Iterator<E> {
		......
	}
}

ArrayList实现了List接口的iterator方法,返回一个内部类的实例,这个实例包含了对集合中元素的迭代等操作

--------Iterator接口(角色:Iterator)---------

public interface Iterator<E> {
	.......
    boolean hasNext();
    E next();
    .......
}

Iterator接口负责提供对集合进行遍历,hasNext方法判断集合是否可以调用next方法,next()方法则是取得当前下标的元素并将下标只想下一个元素。
即:next()方法由两个操作。取出当前元素、将下标状态指向下一个迭代的元素

--------------Itr类(角色:ConcreteIterator)------------,继承了Iterator接口,并在java中是ArrayList的内部类。包含了对list集合中的元素的迭代操作。

private class Itr implements Iterator<E> {
        int cursor;       // 迭代器游标,默认值0
        int lastRet = -1; // 默认值-1标识没有找到改下表元素
        int expectedModCount = modCount;

        Itr() {}
		
		//判断迭代器中的下标是否等于集合的元素个数
        public boolean hasNext() {
            return cursor != size;
        }

       
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            //将集合中的数组委托给迭代器类
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        public void remove() {
           ......
        }

      
        public void forEachRemaining(Consumer<? super E> consumer) {
           ......
        }
		//判断迭代时集合是否被修改,假如被修改(增删改操作),则抛出异常
        final void checkForComodification() {
        	//modCount 是集合修改时自动+1
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

Itr时Iterator的实现类,hasNext方法判断下标是否与ArrayList类中的元素长度一致,不一致则返回true,可调用next方法;一致则返回false,已迭代最后一个元素。

next方法中,将ArrayList类中的成员变量elementData数组委托给迭代器,返回当前只想的数组的元素,并将下标指向下一个迭代元素。

简述Iterator中登场的角色:

  1. Iterator(迭代器):该角色负责定义按顺序逐个遍历元素的接口(API)。在以上程序中,由Iterator扮演这个角色,它定义了两个方法。其中,hasNext 方法用于判断是否存在下一个元素,next 方法用于获取该元素
  2. ConcreteIterator(具体的迭代器):该角色负责实现Iterator角色所定义的接口(API)。以上程序中,由 Itr 类扮演这个角色。该角色半酣了遍历集合所需要的信息,用于持有元素实例的信息保存在elementData 中,指向下一个元素的下标保存在cursor中。
  3. Aggregate(集合):该角色定义创建Iterator角色的接口(API),这个接口是一个方法,会创建出“会按顺序访问我内部元素的迭代器”。以上程序中由List接口扮演这个角色
  4. ConcreteAggregate(具体的集合):该角色负责实现Aggregate角色所定义的接口(API)。会创建出具体的Iterator角色,即ConcreteIterator角色。以上程序中由ArrayList扮演这个角色。

WARN:
其中,Aggregate和Iterator对应,当Aggregate角色的具体实现的API发生了改变,则Iterator的具体实现也需要相应的改变。因为Iterator需要知道Aggregate中是怎么实现的,才能对这个集合做出遍历等操作。

优点:
1、简化的遍历的结构,提供了统一的接口,隐藏了集合的数据细节,可以直接对集合进行遍历
2、实现了功能分离,将集合委托给外部类访问,符合类的设计原则
3、提供了多种方式访问集合(升序、倒叙、跳跃式等等)

引用的文章 https://blog.csdn.net/elise_zhou/article/details/45689161

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值