设计模式之迭代器模式
迭代器模式
定义:提供一种方法,顺序访问一个集合对象中的各个元素,而又不暴露该对象的内部表示
类型:行为型
适用场景:
- 访问一个集合对象的内容而无需暴露它的内部表示
- 为遍历不同的集合结构提供一个统一的接口
优点:
- 分离了集合对象的遍历行为
- 封装性良好,用户只需要得到迭代器就可以遍历,而对于遍历算法则不用去关心
缺点:
- 类的个数成对增加
UML类图:
抽象容器角色(Aggregate):负责提供创建具体迭代器角色的接口,一般是一个接口,提供一个iterator()方法,例如java中的Collection接口,List接口,Set接口等。
具体容器角色(ConcreteAggregate):就是实现抽象容器的具体实现类,比如List接口的有序列表实现ArrayList,List接口的链表实现LinkedList,Set接口的哈希列表的实现HashSet等。
抽象迭代器角色(Iterator):负责定义访问和遍历元素的接口。
具体迭代器角色(ConcreteIterator):实现迭代器接口,并要记录遍历中的当前位置。
示例
举一个简单的例子,有一个书柜,书柜上放有一堆的书籍,我们在可以对这个书柜存放书籍或移除书籍,也可以查看所有书籍的信息,这里的目的是遍历获取到所有的书籍信息
- 书籍类
/**
* 书籍
*/
public class Book {
/**
* 书籍名称
*/
private String name;
/**
* 书籍价格
*/
private double price;
public Book(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
- 书籍集合接口
/**
* 书籍集合接口
*/
public interface BookAggregate {
/**
* 添加书籍
* @param book
*/
void addCourse(Book book);
/**
* 移除书籍
* @param book
*/
void removeCourse(Book book);
/**
* 获取书籍迭代器
* @return
*/
Iterator getBookIterator();
}
- 书籍集合实现类
/**
* 书籍集合实现类
*/
public class BookAggregateImpl implements BookAggregate{
private List<Book> bookList = new ArrayList<>();
@Override
public void addCourse(Book book) {
bookList.add(book);
}
@Override
public void removeCourse(Book book) {
bookList.remove(book);
}
@Override
public Iterator getBookIterator() {
return new BookIterator(bookList);
}
}
- 迭代器接口
/**
* 迭代器接口
*/
public interface Iterator {
/**
* 获取下一个书籍元素
* @return
*/
Book nextBook();
/**
* 是否是最后一个
* @return
*/
boolean isLast();
}
- 具体书籍迭代器
package com.yaolong.demo.designpattern.behaviour.iterator;
import java.util.List;
/**
* 具体书籍迭代器
*/
public class BookIterator implements Iterator {
private List<Book> bookList;
private int position;
private Book book;
public BookIterator(List bookList) {
this.bookList = bookList;
}
@Override
public Book nextBook() {
System.out.println("返回书籍,位置是" + position);
book = bookList.get(position);
position++ ;
return book;
}
@Override
public boolean isLast() {
if(position < bookList.size()){
return false;
}
return true;
}
}
- 客户端
/**
* 迭代器模式
*/
public class Client {
public static void main(String[] args) {
Book book1 = new Book("辟邪剑谱", 20);
Book book2 = new Book("葵花宝典", 32);
Book book3 = new Book("九阳神功", 40);
Book book4 = new Book("九阴真经", 50);
BookAggregate bookAggregate = new BookAggregateImpl();
bookAggregate.addCourse(book1);
bookAggregate.addCourse(book2);
bookAggregate.addCourse(book3);
bookAggregate.addCourse(book4);
Iterator bookIterator = bookAggregate.getBookIterator();
while(!bookIterator.isLast()){
System.out.println(bookIterator.nextBook());
}
//移除后
System.out.println("");
System.out.println("移除一本书后:");
bookIterator = bookAggregate.getBookIterator();
bookAggregate.removeCourse(book1);
while(!bookIterator.isLast()){
System.out.println(bookIterator.nextBook());
}
}
}
返回书籍,位置是0
Book{name='辟邪剑谱', price=20.0}
返回书籍,位置是1
Book{name='葵花宝典', price=32.0}
返回书籍,位置是2
Book{name='九阳神功', price=40.0}
返回书籍,位置是3
Book{name='九阴真经', price=50.0}移除一本书后:
返回书籍,位置是0
Book{name='葵花宝典', price=32.0}
返回书籍,位置是1
Book{name='九阳神功', price=40.0}
返回书籍,位置是2
Book
以上的例子就是我们自定义了一个迭代器接口并实现了迭代器的功能,BookAggregate实例将集合的位置判断、遍历行为委托给了Iterator实例,而不需要向客户端暴露自己内部的集合结构。通常为了方便维护,这个迭代器实现我们以一个内部类的进行提供。实际上,我们一般很少自己去定义迭代器接口,如jdk中提供了java.lang.Iterable(相当于BookAggregate)和java.util.Iterator(相当于我们上面定义的Iterator)都是现成的接口,如果我们自己定义的数据结构需要实现遍历输出,实现这两个接口即可
相关的设计模式
- 迭代器模式和访问者模式
都是迭代地访问集合中的各个元素,访问者模式中扩展开放的部分是作用于对象的操作上,而在迭代器模式中,扩展开放的部分是在集合对象的种类上,二者的实现方式上有很大的区别
使用典范
- java.util.ArrayList