Iterator设计模式
简介:
Iterator设计模式在数据集合中按照顺序遍历集合. 英语单词Iterate有反复做某件事情的意思, 称为迭代器
例子说明:
名字 |
说明 |
Aggregate |
表示集合的接口 |
Iterator |
遍历集合的接口 |
Book |
表示书的类 |
BookShelf |
表示书架的类 |
BookShelfIterator |
遍历书架的类 |
DesignApplicationTests |
所有的测试方法类 |
代码
Aggregate接口(Aggregate.java)
/**
* 迭代器类
*
* @author MARKCC
* @date 2019/2/6-16:32
* @email markerccc@163.com
*/
public interface Aggregate {
/**
* 用于遍历集合的迭代器方法
*
* @return 迭代器类
*/
Iterator iterator();
}
Iterator接口(Iterator.java)
/**
* 用于遍历集合中的元素
*
* @author MARKCC
* @date 2019/2/6-16:33
* @email markerccc@163.com
*/
public interface Iterator {
/**
* 当集合中存在下一个元素的时候,该方法返回true
*
* @return Boolean
*/
Boolean hasNext();
/**
* 返回的是集合中的下一个元素
*
* @return 集合中的下一个元素
*/
Object next();
}
Book类(Book.java)
package com.mark.model.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.*;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* 书
*
* @author MARKCC
* @date 2019/2/6-16:35
* @email markerccc@163.com
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@TableName("book")
public class Book extends Model<Book> {
private static final long serialVersionUID = 1L;
@TableId
private Long id;
@TableField("create_time")
private Date createTime;
@TableField(value = "update_time", update = "now()")
private Date updateTime;
@TableField("del_flag")
private String delFlag;
@TableField("name")
private String name;
@Override
protected Serializable pkVal() {
return this.id;
}
}
BookShelf类(BookShelf.java)
/**
* 书架
*
* @author MARKCC
* @date 2019/2/6-16:42
* @email markerccc@163.com
*/
public class BookShelf implements Aggregate {
private transient Book[] books;
/**
* ArrayList中用到了类似的用法, 请看modCount, modCount的用处是防止集合在遍历的时候被修改, 产生并发修改异常
*/
private int last = 0;
private int size;
/**
* 指定书架的最大容量
*
* @param maxsize 最大容量
*/
public BookShelf(Integer maxsize) {
this.size = maxsize;
this.books = new Book[maxsize];
}
/**
* 拿到索引位置上的书
*
* @param index 索引
* @return 该索引上的书
*/
public Book getBookAt(int index) {
//这里借鉴ArrayList, 防止产生索引越界
if (index >= size) {
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
return books[index];
}
/**
* 添加书本的方法
*
* @param book 书本
*/
public void appendBook(Book book) {
if (last >= size) {
throw new IndexOutOfBoundsException(outOfBookOutMsg(last));
}
this.books[last] = book;
last++;
}
/**
* 获得长度
*
* @return
*/
public int getLength() {
return last;
}
@Override
public Iterator iterator() {
return new BookShelfIterator(this);
}
private String outOfBoundsMsg(int index) {
// 返回当前的索引, 和元素个数
return "Index: " + index + ", Size: " + size;
}
private String outOfBookOutMsg(int index) {
return "Index: " + index + ", 书架Size: " + size;
}
}
BookShelfIterator类(BookShelfIterator.java)
/**
* @author MARKCC
* @date 2019/2/6-16:58
* @email markerccc@163.com
*/
public class BookShelfIterator implements Iterator {
private BookShelf bookShelf;
private int index;
BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
this.index = 0;
}
@Override
public boolean hasNext() {
return index < bookShelf.getLength();
}
@Override
public Object next() {
Book book = bookShelf.getBookAt(index);
index++;
return book;
}
}
测试方法:
/**
* 迭代器设计模式
*/
@Test
public void iteratorTest() {
BookShelf bookShelf = new BookShelf(3);
bookShelf.appendBook(new Book(1L, new Date(), null, "0", "A"));
bookShelf.appendBook(new Book(2L, new Date(), null, "0", "B"));
bookShelf.appendBook(new Book(3L, new Date(), null, "0", "C"));
Iterator iterator = bookShelf.iterator();
while (iterator.hasNext()) {
Book book = (Book) iterator.next();
System.out.println(book.getName());
}
}
分析
1. Iterator(迭代器)
该角色负责定义按顺序逐个遍历元素的接口(API
)
方法 |
作用 |
hasNext |
用于判断是否存在下一个元素 |
next |
用于获取元素 |
2. ConcreteIterator(具体的迭代器)
该角色负责实现Iterator
角色所定义的接口(API
)
扮演者 |
作用 |
BookShelfIterator |
该角色包含了遍历集合所需的信息 |
字段 |
作用 |
bookShelf |
实例 |
index |
指向的书的下标 |
3. Aggreagte(集合)
该角色负责创建Iterator
角色的接口(API
)
扮演者 |
作用 |
Aggregate |
定义了iterator() |
4. ConcreateAggregate(具体的集合)
该角色负责实现Aggregate
角色所定义的接口(API
)
作用 |
它会创建出具体的Iterator 角色, 即ConcreteIterator 角色 |
扮演者 |
作用 |
BookShelf |
实现了Iterator 方法 |
总结
1. 不管怎么如何变化, 都可以使用Iterator
while (iterator.hasNext()) {
Book book = (Book) iterator.next();
System.out.println(book.getName());
}
分析1 : |
这里只使用了Iterator 的hasNext() 和next() , 并没有调用BookShelf的方法. 也就是说, 这里的while循环并不依赖于BookShelf实现
|
分析2 : |
如果编写BookShelf 的开发人员决定放弃数组来管理书本, 而是使用集合取代, 不管BookShelf 如何变化, 只要BookShelf 的Iterator 都能正确的返回Iterator 实例, 即不对上面的while 循环做任何修改, 代码可以正常工作 |
分析3: |
设计模式的作用就是帮助我们编写可复用的类. 所谓可复用, 就是将类实现为组件, 当一个组件发生改变时, 不需要对其他的组件进行修改, 或者只需要很小的修改即可, 这就是为什么Iterator 的方法返回值是Iterator 类型了, 而不是BookShelfIterator 类了 |
2. 难以理解的抽象类和接口
分析: |
人们常常使用ConcreateAggregate 角色和ConcreateIterator 角色编程, 而不使用Aggregate 和Iterator 接口, 他们总想用具体的类来解决所有的问题. 这样很容易导致类之间的强耦合, 难以复用, 为了弱化类之间的耦合, 进而使类更加容易作为组件被再次利用, 需要常常使用抽象类和接口 |
3. 对应关系
Aggregate |
Iterator |
ConcreateAggreagte |
ConcreateIterator |
分析: |
如果BookShelf 的实现发生了改变, 即getBookAt() 发生改变, 我们必须修改BookShelfIterator 类 |
4. 下一个
分析: |
next() 方法是返回当前的元素, 并指向下一个元素 |
5. 最后一个
分析: |
hasNext() 确认接下来是否可以调用next方法 |
6. 多个Iterator
分析: |
将遍历功能置于Aggregate角色之外是Iterator 模式的一个特征. 根据这个特征, 可以针对一个ConcreateAggregate 角色编写多个ConcreateIterator 角色, 即一个集合可以编写多个迭代器 |
7. 迭代器的种类多种多样
种类 |
从最后开始向前遍历 |
即可以从前向后遍历, 也可以从后向前遍历(即有next() 也有previous()
|
指定下标进行跳跃式的遍历 |
8. 不需要deleteIterator
分析: |
在Java 中, 没有被使用的对象实例将会自动被删除(GC ), 因此, 在Iterator 中不需要与其对应的deleteIterator()
|
9. 相关的设计模式
Iterator 模式 |
没有在Iterator接口中对取出元素进行处理 |
Visitor 模式 |
遍历集合的过程中, 对元素进行相同的处理 |
Composite 模式 |
具有递归结构的模式, 在其中使用Iterator模式比较困难 |
Factory Method 模式 |
在Iterator 方法中生成Iterator的实例时可能会使用Factory Method 模式 |
分析: |
在遍历集合的过程中对元素进行固定的处理是常有的, Visitor 模式正是为了应对这种需求出现的, 在访问元素集合的过程中对元素进行相同处理, 这种模式就是Visitor 模式 |
借鉴
图解设计模式(结城浩 著)