对迭代器模式的理解

发布于:2025-04-09 ⋅ 阅读:(41) ⋅ 点赞:(0)

一、场景

  • 以简化版“图书馆书籍管理系统”介绍迭代器模式的好处。
  • 假设图书馆中有多个书架,每个书架上存放着不同数量的书籍。我们需要实现一个功能,能够遍历所有书架上的书籍,并打印出每本书的信息。

二、不采用迭代器模式

1、代码

// 书类
public class Book {
    private String title;

    public Book(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }
}

// 书架类
public class BookShelf {
    private Book[] books;
    private int last = 0;

    public BookShelf(int maxSize) {
        this.books = new Book[maxSize];
    }

    public void appendBook(Book book) {
        if (last >= books.length) {
            throw new IllegalArgumentException("书架已满");
        }

        this.books[last] = book;
        last++;
    }

    public int getLength() {
        return last;
    }

    public Book getBookAt(int i) {
        if (i < last && i >= 0) {
            return books[i];
        }

        throw new IllegalArgumentException("书架索引越界");
    }
}

// 图书馆类
@Getter
@AllArgsConstructor
public enum BookShelfEnum {
    CS_BOOK_SHELF("计算机书架", 0),
    LITERATURE_BOOK_SHELF("文学书架", 1),
    NOVEL_BOOK_SHELF("小说书架", 2);

    private final String name;
    private final int index;
}

public class Library {
    private BookShelf[] bookShelves;

    public Library() {
        this.bookShelves = new BookShelf[3];
    }

    public void appendBook(BookShelfEnum shelfEnum , Book book) {
        if (shelfEnum == null) {
            throw new IllegalArgumentException("书架类型不能为null");
        }

        BookShelf bookShelf = bookShelves[shelfEnum.getIndex()];
        if (bookShelf == null) {
            bookShelves[shelfEnum.getIndex()] = new BookShelf(5);
            bookShelf = bookShelves[shelfEnum.getIndex()];
        }

        bookShelf.appendBook(book);
    }

    public int getNumShelves() {
        return bookShelves.length;
    }

    public BookShelf getBookShelfAt(int i) {
        if (i < 0 || i >= bookShelves.length) {
            throw new IllegalArgumentException("书架索引越界");
        }

        return bookShelves[i];
    }
}

// 客户端
public class Main {
    public static void main(String[] args) {
        Library library = new Library();

        library.appendBook(BookShelfEnum.CS_BOOK_SHELF, new Book("Java编程思想"));
        library.appendBook(BookShelfEnum.CS_BOOK_SHELF, new Book("Effective Java"));

        library.appendBook(BookShelfEnum.LITERATURE_BOOK_SHELF, new Book("三国演义"));
        library.appendBook(BookShelfEnum.LITERATURE_BOOK_SHELF, new Book("红楼梦"));

        library.appendBook(BookShelfEnum.NOVEL_BOOK_SHELF, new Book("白夜行"));
        library.appendBook(BookShelfEnum.NOVEL_BOOK_SHELF, new Book("简爱"));

        // 遍历所有书籍
        for (int i = 0; i < library.getNumShelves(); i++) {
            BookShelf bookShelf = library.getBookShelfAt(i);
            if (bookShelf == null) {
                continue;
            }

            for (int j = 0; j < bookShelf.getLength(); j++) {
                Book book = bookShelf.getBookAt(j);
                System.out.println(book.getTitle());
            }
        }
    }
}

2、缺点

  • 不采用迭代器模式时,当我们去遍历图书馆的书籍的时候,不得不知道图书馆是如何存储书籍的。

    • 首先,我们得知道图书馆有书架组成,我们需要遍历若干个书架。
    • 其次,对于每个书架,如果有书的话,我们要遍历每本书。
  • 但我们并不希望客户端知道图书馆是如何存储书籍的。这时候怎么办?需要迭代器模式。

三、采用迭代器模式

  • 迭代器模式是一种行为设计模式, 让我们能在不暴露集合底层存储结构 (列表、 栈和树等) 的情况下遍历集合中所有的元素。

1、代码

// 书架类
public class BookShelf implements Iterable<Book> {
    private Book[] books;
    private int last = 0;

    public BookShelf(int maxSize) {
        this.books = new Book[maxSize];
    }

    public void appendBook(Book book) {
        this.books[last] = book;
        last++;
    }

    private Book getBookAt(int index) {
        return books[index];
    }

    private int getLength() {
        return last;
    }

    @Override
    public Iterator<Book> iterator() {
        return new BookIterator(this);
    }

    private class BookIterator implements Iterator<Book> {
        private BookShelf bookShelf;
        private int index;

        public BookIterator(BookShelf bookShelf) {
            this.bookShelf = bookShelf;
            this.index = 0;
        }

        @Override
        public boolean hasNext() {
            return index < bookShelf.getLength();
        }

        @Override
        public Book next() {
            return bookShelf.getBookAt(index++);
        }
    }
}

// 图书馆类
public class Library implements Iterable<Book> {
    private BookShelf[] bookShelves;

    public Library() {
        this.bookShelves = new BookShelf[3];
    }

    public void appendBook(BookShelfEnum shelfEnum, Book book) {
        if (shelfEnum == null) {
            throw new IllegalArgumentException("书架类型不能为null");
        }

        BookShelf bookShelf = bookShelves[shelfEnum.getIndex()];
        if (bookShelf == null) {
            bookShelves[shelfEnum.getIndex()] = new BookShelf(5);
            bookShelf = bookShelves[shelfEnum.getIndex()];
        }

        bookShelf.appendBook(book);
    }

    @Override
    public Iterator<Book> iterator() {
        return new LibraryIterator(this);
    }

    private class LibraryIterator implements Iterator<Book> {
        private Library library;
        private int bookShelfIndex = 0;
        private Iterator<Book> bookIterator;

        public LibraryIterator(Library library) {
            this.library = library;
        }

        @Override
        public boolean hasNext() {
            if (bookIterator != null && bookIterator.hasNext()) {
                return true;
            }

            while (bookShelfIndex < library.bookShelves.length) {
                BookShelf bookShelf = library.bookShelves[bookShelfIndex++];
                if (bookShelf == null) {
                    continue;
                }

                bookIterator = bookShelf.iterator();
                if (bookIterator.hasNext()) {
                    return true;
                }
            }

            return false;
        }

        @Override
        public Book next() {
            return bookIterator.next();
        }
    }
}

// 客户端
public class Main {
    public static void main(String[] args) {
        Library library = new Library();

        library.appendBook(BookShelfEnum.CS_BOOK_SHELF, new Book("Java编程思想"));
        library.appendBook(BookShelfEnum.CS_BOOK_SHELF, new Book("Effective Java"));

        library.appendBook(BookShelfEnum.LITERATURE_BOOK_SHELF, new Book("三国演义"));
        library.appendBook(BookShelfEnum.LITERATURE_BOOK_SHELF, new Book("红楼梦"));

        library.appendBook(BookShelfEnum.NOVEL_BOOK_SHELF, new Book("白夜行"));
        library.appendBook(BookShelfEnum.NOVEL_BOOK_SHELF, new Book("简爱"));

        // 遍历所有书籍
        Iterator<Book> iterator = library.iterator();
        while (iterator.hasNext()) {
            Book book = iterator.next();
            System.out.println(book.getTitle());
        }
    }
}

2、优点

  • 采用迭代器模式后,遍历图书馆的所有书籍,客户端完全不知道图书馆是如何存储书籍的。

四、总结

  • 采用迭代器模式的思路:

    • (1)理解需求:如果自定义了一个较复杂结构,客户端又需要遍历这个复杂结构的元素,这时候要想到使用迭代器模式。

    • (2)复杂结构要实现Iterator结构:

      public class ComplexStructure implements Iterator<Element>  {
      
      	@Override
          public Iterator<Element> iterator() {
              return new ComplexStructureIterator(this);
          }
      
          private class ComplexStructureIterator implements Iterator<Element> {
              private ComplexStructure complexStructure;
      
              public ComplexStructureIterator(ComplexStructure complexStructure) {
                  this.complexStructure = complexStructure;
              }
      
              @Override
              public boolean hasNext() {
                  // 待实现
              }
      
              @Override
              public Element next() {
                  // 待实现
              }
          }
      }
      
    • (3)客户端使用迭代器:

      Iterator<Element> iterator = library.iterator();
      while (iterator.hasNext()) {
      	Element element = iterator.next();
      	...
      }