迭代器模式
# 迭代器模式
迭代器模式可以将集合的遍历逻辑与集合本身解耦,使得集合的实现和遍历算法可以独立变化。此外,迭代器模式还可以隐藏集合的内部结构,提供更简洁的接口给客户端使用。
# 定义
迭代器模式是一种行为设计模式,它允许你按顺序遍历集合对象中的元素,而无需暴露集合的内部表示。使用迭代器模式,你可以通过统一的接口遍历不同类型的集合,而无需了解集合的具体实现。
# 结构
迭代器(Iterator):定义了访问和遍历集合元素的接口。它通常包含方法如获取下一个元素next()、判断是否还有下一个元素hasNext()等。
具体迭代器(Concrete Iterator):实现迭代器接口,负责实现具体的遍历逻辑,包括管理当前位置、返回当前元素等。
集合(Collection):定义了创建迭代器对象的接口,一般会提供一个方法来获取迭代器实例,如Collection、List接口方法:iterator()。
具体集合(Concrete Collection):实现集合接口,负责创建具体迭代器对象,如ArrayList中方法:iterator()。具体集合通常会包含一个内部数据结构,如数组、链表等。
- img: https://bitouyun.com/images/design-pattern/iterator.png
link: https://bitouyun.com/images/design-pattern/iterator.png
name: 迭代器模式
2
3
# 优点
分离集合对象与遍历逻辑:迭代器模式将集合对象与遍历逻辑分离,使得它们可以独立变化。集合对象可以专注于实现自身的数据结构和操作,而遍历逻辑则由迭代器负责实现。这样可以提高代码的可维护性和灵活性。
统一遍历接口:迭代器模式定义了统一的遍历接口,客户端代码可以通过迭代器的通用方法进行遍历操作,而无需关心具体的集合类型和内部实现细节。这简化了客户端代码,提供了更简洁的接口。
支持多种遍历方式:迭代器模式可以提供不同类型的迭代器,如正向迭代器、反向迭代器等,以满足不同的遍历需求。这使得客户端可以灵活地选择适合自己需求的遍历方式。
隐藏集合内部结构:通过迭代器模式,集合的内部结构被封装起来,对客户端代码隐藏起来。这提高了集合的安全性和封装性,防止直接访问和修改集合元素。
# 缺点
遍历过程中集合修改:使用迭代器遍历集合时,如果在遍历期间集合发生了修改(如增加、删除元素),可能会导致迭代器的状态与实际集合的状态不一致,引发错误。为了避免这种情况,需要在遍历时进行额外的同步或者使用支持并发修改的迭代器。
迭代器的创建和管理:迭代器模式需要额外的代码来创建和管理迭代器对象,这增加了一定的复杂性。在某些语言中,如 C++,需要手动释放迭代器对象的资源。
对于简单集合的过度设计:对于一些简单的集合类型,引入迭代器模式可能会增加代码的复杂性,不如直接使用语言提供的迭代方式(如 for-each 循环)来进行遍历。
# 应用场景
迭代器模式在提供集合遍历的灵活性、封装性和统一接口方面具有明显的优点,但在处理遍历期间的集合修改和迭代器的创建与管理方面需要谨慎处理。在具体应用时需要根据场景和需求权衡利弊。
需要按顺序遍历一个集合对象中的元素,并且不希望暴露集合的内部表示时,可以使用迭代器模式。它提供了一种统一的方式来遍历集合,无论集合的具体类型如何变化,遍历代码都可以保持一致。
需要对不同类型的集合提供统一的遍历接口,迭代器模式可以解决不同类型集合的遍历问题,它定义了通用的遍历接口,使得客户端代码可以使用相同的方式来遍历不同类型的集合。这样可以提高代码的可重用性和灵活性。
需要隐藏集合的内部结构,通过迭代器模式,集合的内部结构可以被封装起来,对客户端代码隐藏。这有助于提高集合的安全性和封装性,避免直接访问和修改集合元素。
# 示例代码
场景
使用迭代器模式遍历图书馆的图书
/**
* 迭代器接口
*/
public interface Iterator {
// 是否还有下一个元素
boolean hasNext();
// 获取下一个元素
Book next();
}
2
3
4
5
6
7
8
9
10
11
/**
* 图书馆具体迭代器
*/
public class LibraryIterator implements Iterator {
private int index;
private List<Book> books;
public LibraryIterator(List<Book> books) {
this.books = books;
}
@Override
public boolean hasNext() {
return index < books.size();
}
@Override
public Book next() {
if (hasNext()) {
Book book = books.get(index);
index++;
return book;
}
return null;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* 图书馆接口
*/
public interface ILibrary {
void addBook(Book book);
// 获取迭代器
Iterator iterator();
}
2
3
4
5
6
7
8
9
/**
* 图书馆类
*/
public class Library implements ILibrary {
private List<Book> books;
public Library() {
this.books = new ArrayList<>();
}
@Override
public void addBook(Book book) {
books.add(book);
}
// 获取迭代器
@Override
public Iterator iterator() {
return new LibraryIterator(books);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 图书类
*/
@Getter
@AllArgsConstructor
public class Book {
private String title;
private String author;
}
2
3
4
5
6
7
8
9
/**
* 测试类
*/
@Slf4j
public class Client {
public static void main(String[] args) {
ILibrary library = new Library();
library.addBook(new Book("Book1", "Author1"));
library.addBook(new Book("Book2", "Author2"));
library.addBook(new Book("Book3", "Author3"));
Iterator bookIterator = library.iterator();
while (bookIterator.hasNext()) {
Book book = bookIterator.next();
log.info("图书:{},作者:{}", book.getTitle(), book.getAuthor());
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Make sure to add code blocks to your code group