现在我们来学习迭代器模式。这个模式非常常见,它提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。
“提供一种方法顺序访问一个聚合对象 (Aggregate) 中各个元素,而又不暴露该对象的内部表示。” (Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.)
想象一下你看电视换频道:
迭代器模式允许你遍历集合的元素,而无需关心集合是如何实现的(例如,是 ArrayList
、LinkedList
、HashSet
还是自定义的集合)。
迭代器模式的主要目的:
MP3播放器的播放列表:
书本的目录或页码:
餐厅服务员按顺序上菜:
迭代器模式通常包含以下角色:
hasNext()
(或 hasMore()
)、next()
(或 currentItem()
)等方法。有时也可能包含 first()
、isDone()
等。createIterator()
或 iterator()
。hasNext()
和 next()
方法来顺序访问聚合中的元素。range
keyword over slices/maps, C# IEnumerable
/IEnumerator
)。优点:
缺点:
让我们以一个简单的书架 (BookShelf) 和书 (Book) 的例子来说明。
// book.go
package aggregate
// Book 元素类
type Book struct {
Name string
}
func NewBook(name string) *Book {
return &Book{Name: name}
}
// Book.java
package com.example.aggregate;
public class Book {
private String name;
public Book(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
// aggregate.go (Aggregate interface)
package aggregate
import "../iterator"
// Aggregate 聚合接口
type Aggregate interface {
CreateIterator() iterator.Iterator
}
// Aggregate.java (Aggregate interface)
package com.example.aggregate;
import com.example.iterator.Iterator;
public interface Aggregate {
Iterator<Book> createIterator();
}
// bookshelf.go (ConcreteAggregate)
package aggregate
import "../iterator"
// BookShelf 具体聚合
type BookShelf struct {
books []*Book
last int // 当前书的数量,也作为下一个可添加位置的索引
}
func NewBookShelf(maxSize int) *BookShelf {
return &BookShelf{
books: make([]*Book, maxSize),
last: 0,
}
}
func (bs *BookShelf) AddBook(book *Book) {
if bs.last < len(bs.books) {
bs.books[bs.last] = book
bs.last++
}
// else: bookshelf is full, handle error or ignore
}
func (bs *BookShelf) GetBookAt(index int) *Book {
if index >= 0 && index < bs.last {
return bs.books[index]
}
return nil
}
func (bs *BookShelf) GetLength() int {
return bs.last
}
// CreateIterator 实现 Aggregate 接口
func (bs *BookShelf) CreateIterator() iterator.Iterator {
// Go 中,具体迭代器需要知道具体聚合的类型以访问其内部数据
// 所以这里直接传递 bs 给 BookShelfIterator 的构造函数
return iterator.NewBookShelfIterator(bs) // 假设 BookShelfIterator 在 iterator 包中
}
// BookShelf.java (ConcreteAggregate)
package com.example.aggregate;
import com.example.iterator.BookShelfIterator;
import com.example.iterator.Iterator;
import java.util.ArrayList;
import java.util.List;
public class BookShelf implements Aggregate {
private List<Book> books;
public BookShelf() {
this.books = new ArrayList<>();
}
public void addBook(Book book) {
this.books.add(book);
}
public Book getBookAt(int index) {
if (index >= 0 && index < books.size()) {
return books.get(index);
}
return null;
}
public int getLength() {
return books.size();
}
@Override
public Iterator<Book> createIterator() {
return new BookShelfIterator(this); // 'this' is the ConcreteAggregate
}
}
// iterator.go (Iterator interface)
package iterator
// Iterator 迭代器接口
type Iterator interface {
HasNext() bool
Next() interface{} // 返回 interface{} 以便通用,具体使用时需要类型断言
}
// Iterator.java (Iterator interface - generic)
package com.example.iterator;
public interface Iterator<T> {
boolean hasNext();
T next();
}
// bookshelf_iterator.go (ConcreteIterator)
package iterator
import "../aggregate" // 导入 aggregate 包以获取 BookShelf 类型
// BookShelfIterator 具体迭代器
type BookShelfIterator struct {
bookShelf *aggregate.BookShelf // 持有具体聚合的引用
index int
}
// NewBookShelfIterator 构造函数,接收具体聚合对象
func NewBookShelfIterator(bookShelf *aggregate.BookShelf) *BookShelfIterator {
return &BookShelfIterator{
bookShelf: bookShelf,
index: 0,
}
}
func (bsi *BookShelfIterator) HasNext() bool {
return bsi.index < bsi.bookShelf.GetLength()
}
func (bsi *BookShelfIterator) Next() interface{} {
if bsi.HasNext() {
book := bsi.bookShelf.GetBookAt(bsi.index)
bsi.index++
return book
}
return nil // Or panic, or return an error
}
// BookShelfIterator.java (ConcreteIterator)
package com.example.iterator;
import com.example.aggregate.Book;
import com.example.aggregate.BookShelf;
public class BookShelfIterator implements Iterator<Book> {
private BookShelf bookShelf; // Holds the ConcreteAggregate
private int index;
public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
this.index = 0;
}
@Override
public boolean hasNext() {
return index < bookShelf.getLength();
}
@Override
public Book next() {
if (hasNext()) {
Book book = bookShelf.getBookAt(index);
index++;
return book;
}
return null; // Or throw NoSuchElementException as in java.util.Iterator
}
}
// main.go (示例用法)
/*
package main
import (
"./aggregate"
"./iterator"
"fmt"
)
func main() {
bookShelf := aggregate.NewBookShelf(4)
bookShelf.AddBook(aggregate.NewBook("Around the World in 80 Days"))
bookShelf.AddBook(aggregate.NewBook("Bible"))
bookShelf.AddBook(aggregate.NewBook("Cinderella"))
bookShelf.AddBook(aggregate.NewBook("Daddy-Long-Legs"))
it := bookShelf.CreateIterator()
fmt.Println("Iterating through BookShelf:")
for it.HasNext() {
book, ok := it.Next().(*aggregate.Book) // 类型断言
if ok && book != nil {
fmt.Println(book.Name)
}
}
// Go 的 range 关键字本身就是一种迭代器模式的体现
fmt.Println("\nUsing Go's built-in range (for slices, not directly for our custom BookShelf without extra methods):")
// 要让 range 直接作用于 BookShelf,BookShelf 需要实现特定的接口或提供一个可供 range 的 slice
// 例如,可以给 BookShelf 添加一个方法 `GetBooksSlice() []*Book`
// booksSlice := bookShelf.GetBooksSlice() // 假设有这个方法
// for _, book := range booksSlice {
// fmt.Println(book.Name)
// }
}
*/
// Main.java (示例用法)
/*
package com.example;
import com.example.aggregate.Book;
import com.example.aggregate.BookShelf;
import com.example.iterator.Iterator;
public class Main {
public static void main(String[] args) {
BookShelf bookShelf = new BookShelf();
bookShelf.addBook(new Book("Design Patterns: Elements of Reusable Object-Oriented Software"));
bookShelf.addBook(new Book("Effective Java"));
bookShelf.addBook(new Book("Clean Code"));
bookShelf.addBook(new Book("The Pragmatic Programmer"));
Iterator iterator = bookShelf.createIterator();
System.out.println("Iterating through BookShelf:");
while (iterator.hasNext()) {
Book book = iterator.next();
System.out.println(book.getName());
}
// Java's enhanced for loop (for-each loop) uses the Iterator pattern implicitly
// if the collection implements java.lang.Iterable
System.out.println("\nIterating using Java's enhanced for loop (if BookShelf implements Iterable):");
// To use the enhanced for loop, BookShelf would need to implement java.lang.Iterable
// public class BookShelf implements Aggregate, Iterable {
// @Override
// public java.util.Iterator iterator() {
// return new BookShelfIterator(this); // Assuming BookShelfIterator implements java.util.Iterator
// }
// }
// Then you could do:
// for (Book book : bookShelf) {
// System.out.println(book.getName());
// }
}
}
*/
关于语言内建迭代器:
java.util.Iterator
接口和 java.lang.Iterable
接口是迭代器模式的核心。集合类(如 ArrayList
, HashSet
)都实现了 Iterable
,它们的 iterator()
方法返回一个 Iterator
。range
关键字为数组、切片、字符串、map 和 channel 提供了内建的迭代机制。对于自定义类型,通常会提供一个返回 channel 的方法,或者实现类似 Next()
/HasNext()
的方法对,但不像 Java 那样有统一的迭代器接口强制。__iter__()
和 __next__()
) 是语言的核心部分。IEnumerable
和 IEnumerator
接口(以及 yield return
关键字)用于实现迭代。这些内建机制使得在这些语言中使用迭代器模式非常自然和普遍。
迭代器模式是一种基础且广泛应用的设计模式,它优雅地解决了在不暴露集合内部结构的情况下顺序访问集合元素的问题。通过将遍历逻辑封装在独立的迭代器对象中,它增强了代码的封装性、灵活性和可维护性。几乎所有的现代编程语言都在其标准库中深度集成了迭代器模式,使其成为处理集合数据的标准方式。