前言
迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示。它可以让用户透过特定的接口巡访容器中的每一个元素而不用了解底层的实现。
本节,我们就迭代器模式展开详细介绍。
1.迭代器模式中的角色
1.1 Iterator(迭代器)
这个接口负责定义按顺序遍历元素的接口。其中hasNext负责判断是否还存在下一个元素,next方法用于获取该元素并将元素指针后移。
1.2 ConcreteIterator(具体的迭代器)
该类负责实现Iterator所定义的接口,同时包含遍历集合所必要的信息。
1.3 Aggregate(集合)
实现该接口的类都需要实现获取Iterator的方法
1.4 ConcreteAggregate(具体的集合)
该类负责具体实现Aggregate所定义的方法。
2. 代码示例
下面我们以书为例,假设要遍历看书架上每本书的书名,作者,价钱,通过迭代器模式可如下实现。
2.1 定义要迭代的元素(书)
package com.wanlong.design_pattern.action.iterator;
/**
* @author wanlong
* @version 1.0
* @description:
* @date 2022/9/19 17:53
*/
public class Book {
private String bookName;
private Double price;
private String author;
public Book() {
}
public Book(String bookName, Double price, String author) {
this.bookName = bookName;
this.price = price;
this.author = author;
}
@Override
public String toString() {
return "Book{" +
"bookName='" + bookName + '\'' +
", price=" + price +
", author='" + author + '\'' +
'}';
}
}
2.2 定义迭代器
这里使用jdk自己的接口,不重复定义接口,当然也可以自定义接口,代码和jdk类似
package java.util;
import java.util.function.Consumer;
/**
* An iterator over a collection. {@code Iterator} takes the place of
* {@link Enumeration} in the Java Collections Framework. Iterators
* differ from enumerations in two ways:
*
* <ul>
* <li> Iterators allow the caller to remove elements from the
* underlying collection during the iteration with well-defined
* semantics.
* <li> Method names have been improved.
* </ul>
*
* <p>This interface is a member of the
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
* Java Collections Framework</a>.
*
* @param <E> the type of elements returned by this iterator
*
* @author Josh Bloch
* @see Collection
* @see ListIterator
* @see Iterable
* @since 1.2
*/
public interface Iterator<E> {
/**
* Returns {@code true} if the iteration has more elements.
* (In other words, returns {@code true} if {@link #next} would
* return an element rather than throwing an exception.)
*
* @return {@code true} if the iteration has more elements
*/
boolean hasNext();
/**
* Returns the next element in the iteration.
*
* @return the next element in the iteration
* @throws NoSuchElementException if the iteration has no more elements
*/
E next();
/**
* Removes from the underlying collection the last element returned
* by this iterator (optional operation). This method can be called
* only once per call to {@link #next}. The behavior of an iterator
* is unspecified if the underlying collection is modified while the
* iteration is in progress in any way other than by calling this
* method.
*
* @implSpec
* The default implementation throws an instance of
* {@link UnsupportedOperationException} and performs no other action.
*
* @throws UnsupportedOperationException if the {@code remove}
* operation is not supported by this iterator
*
* @throws IllegalStateException if the {@code next} method has not
* yet been called, or the {@code remove} method has already
* been called after the last call to the {@code next}
* method
*/
default void remove() {
throw new UnsupportedOperationException("remove");
}
/**
* Performs the given action for each remaining element until all elements
* have been processed or the action throws an exception. Actions are
* performed in the order of iteration, if that order is specified.
* Exceptions thrown by the action are relayed to the caller.
*
* @implSpec
* <p>The default implementation behaves as if:
* <pre>{@code
* while (hasNext())
* action.accept(next());
* }</pre>
*
* @param action The action to be performed for each element
* @throws NullPointerException if the specified action is null
* @since 1.8
*/
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
2.3 定义集合接口
package com.wanlong.design_pattern.action.iterator;
import java.util.Iterator;
/**
* @author wanlong
* @version 1.0
* @description:
* @date 2022/9/19 17:53
*/
public interface Aggregate<T> {
/**
* 获取迭代器
* @return Iterator
*/
public Iterator<T> getIterator();
}
2.4 定义具体的集合(书架)
package com.wanlong.design_pattern.action.iterator;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* @author wanlong
* @version 1.0
* @description:
* @date 2022/9/19 17:53
*/
public class BookShelf implements Aggregate<Book> {
List<Book> bookList = new ArrayList<>();
@Override
public Iterator<Book> getIterator() {
return new BookShelfIterator(this);
}
public Integer getLength() {
return this.bookList.size();
}
public void appendBook(Book book) {
bookList.add(book);
}
public Book getBookAt(Integer position) {
return this.bookList.get(position);
}
}
2.5 定义具体的迭代器(书架集合迭代器)
package com.wanlong.design_pattern.action.iterator;
import java.util.Iterator;
/**
* @author wanlong
* @version 1.0
* @description:
* @date 2022/9/19 17:54
*/
public class BookShelfIterator implements Iterator<Book> {
private BookShelf bookShelf;
private int index = 0;
public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
}
@Override
public boolean hasNext() {
return bookShelf.getLength() > index;
}
@Override
public Book next() {
Book book = bookShelf.getBookAt(index);
index++;
return book;
}
}
2.6 客户端调用
package com.wanlong.design_pattern.action.iterator;
import org.junit.Test;
import java.util.Iterator;
/**
* @author wanlong
* @version 1.0
* @description:
* @date 2022/9/19 17:54
*/
public class Client {
@Test
public void testIterator() {
BookShelf bookShelf = new BookShelf();
bookShelf.appendBook(new Book("斗破苍穹", 55.0, "天蚕土豆"));
bookShelf.appendBook(new Book("神墓", 63.0, "辰东"));
bookShelf.appendBook(new Book("完美世界", 82.0, "辰东"));
Iterator<Book> iterator = bookShelf.getIterator();
while (iterator.hasNext()) {
Book book = iterator.next();
System.out.println("book = " + book);
}
}
}
代码运行结果:
book = Book{bookName='斗破苍穹', price=55.0, author='天蚕土豆'}
book = Book{bookName='神墓', price=63.0, author='辰东'}
book = Book{bookName='完美世界', price=82.0, author='辰东'}
3.总结
3.1 优缺点
3.1.1 优点
- 分离了集合对象的遍历行为
- 抽象出了迭代器负责集合对象的遍历 , 可以让外部的代码透明的访问集合内部的数据
3.1.2 缺点
- 类的个数成对增加
- 迭代器模式 , 将存储数据 , 遍历数据两个职责拆分 ; 如果新添加一个集合类 , 需要增加该集合类对应的迭代器类 , 类的个数成对增加 , 在一定程度上 , 增加了系统复杂性
3.2 使用场景
- 访问一个聚合对象的内容而无需暴露它的内部表示
- 支持对聚合对象的多种遍历
- 为遍历不同的聚合结构提供一个统一的接口
3.3 常见场景
- jdk提供的ListIterator
- jdk提供的集合遍历iterator等
以上,本人菜鸟一枚,如有错误,请不吝指正。