设计模式-迭代器模式
写在前面
Hello,我是易元,这篇文章是我学习设计模式时的笔记和心得体会。如果其中有错误,欢迎大家留言指正!
案例
假设有一个
Book
类和一个管理书籍的BookCollection
类,我们需要遍历BookCollection类中所有书籍信息。
一、传统实现:直接硬编码遍历逻辑
1. 基础代码
直接在集合类中添加遍历方法
图书类
public class Book { private String title; private String author; private int publishYear; public Book() {} public Book(String title, String author, int publishYear) { this.title = title; this.author = author; this.publishYear = publishYear; } // Getter 和 Setter 方法 public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public int getPublishYear() { return publishYear; } public void setPublishYear(int publishYear) { this.publishYear = publishYear; } @Override public String toString() { return "Book{" + "title='" + title + '\'' + ", author='" + author + '\'' + ", publishYear=" + publishYear + '}'; }
}
图书集合类
public class BookCollection { private List<Book> books; public BookCollection() {} public BookCollection(List<Book> books) { this.books = books; } public void printBooks() { for (Book book : books) { System.out.println(book.toString()); } }
}
测试代码
@Test
public void printBookTest() { List<Book> books = new ArrayList<>(); books.add(new Book("Java编程思想", "Bruce Eckel", 2018)); books.add(new Book("设计模式", "Erich Gamma", 1994)); books.add(new Book("鸟哥的Linux私房菜", "鸟哥", 2010)); BookCollection bookCollection = new BookCollection(books); bookCollection.printBooks();
}
3. 存在的缺陷
以上述代码为例,若需要新的遍历方式(如按作者或出版年份遍历),一种方法是直接在BookCollection
中添加新方法。这会破坏原有代码,每次新增遍历方式都需要修改BookCollection
类。
二、设计模式实现
1. 迭代器模式
迭代器模式提供了一种遍历集合对象元素的方式,而无需暴露其内部表示。它定义了访问集合元素的接口,支持遍历不同的集合结构。
er
- 主要角色:
-
Iterator(迭代器):定义访问和遍历集合元素的接口。
-
ConcreteIterator(具体迭代器):实现迭代器接口,用于遍历集合。
-
Aggregate(集合):定义创建迭代器的接口。
-
ConcreteAggregate(具体集合):实现集合接口,返回具体迭代器实例。
-
2. 使用设计模式对已实现的功能进行重构
迭代器接口
public interface BookIterator { boolean hasNext(); Book getNext();
}
- 定义标准化遍历协议:
-
hasNext()
:检查是否存在下一个元素 -
getNext()
:获取当前元素并后移指针
-
-
解耦集合结构与遍历逻辑的入口
具体迭代器
public class BookCollectionIterator implements BookIterator { private List<Book> books; private int position = 0; public BookCollectionIterator(List<Book> books) { this.books = books; } @Override public boolean hasNext() { return position < books.size(); } @Override public Book getNext() { if (hasNext()) { return books.get(position++); } return null; }
}
-
通过
position
索引跟踪遍历进度 -
集合数据通过构造函数注入,保证迭代器独立性
集合接口
public interface BookAggregate { BookIterator createIterator();
}
具体集合
public class BookCollection implements BookAggregate { private List<Book> books; public BookCollection(List<Book> books) { this.books = books; } @Override public BookIterator createIterator() { return new BookCollectionIterator(books); }
}
-
通过
createIterator()
统一创建迭代器,隐藏实现细节 -
新增迭代器无需修改集合类,只需扩展新实现
测试代码
@Test
public void test_book_def() { List<Book> books = new ArrayList<>(); books.add(new Book("Java编程思想", "Bruce Eckel", 2018)); books.add(new Book("Effective Java", "Joshua Bloch", 2018)); books.add(new Book("设计模式", "Erich Gamma", 1994)); books.add(new Book("鸟哥的Linux私房菜", "鸟哥", 2010)); BookAggregate bookCollection = new BookCollection(books); BookIterator bookIterator = bookCollection.createIterator(); while (bookIterator.hasNext()) { Book book = bookIterator.getNext(); System.out.println(book.toString()); }
}
输出结果
Book{title='Java编程思想', author='Bruce Eckel', publishYear=2018}
Book{title='Effective Java', author='Joshua Bloch', publishYear=2018}
Book{title='设计模式', author='Erich Gamma', publishYear=1994}
Book{title='鸟哥的Linux私房菜', author='鸟哥', publishYear=2010}
3. 增加按照出版年份进行遍历
新增具体集合类
// 按年份过滤的集合
public class BookYearAggregate implements BookAggregate { private List<Book> books; private int targetYear; public BookYearAggregate(List<Book> books, int targetYear) { this.books = books; this.targetYear = targetYear; } @Override public BookIterator createIterator() { return new YearBookIterator(books, targetYear); }
}
新增具体迭代器
// 按出版年份过滤的迭代器
public class YearBookIterator implements BookIterator { private List<Book> books; private int targetYear; private int position = 0; public YearBookIterator(List<Book> books, int year) { this.books = books; this.targetYear = year; } @Override public boolean hasNext() { // 跳过不符合年份的书籍 while (position < books.size()) { if (books.get(position).getPublishYear() == targetYear) { return true; } position++; } return false; } @Override public Book getNext() { if (hasNext()) { return books.get(position++); } return null; }
}
-
按条件过滤:在
hasNext()
中循环查找匹配年份,跳过非目标项 -
独立职责:遍历逻辑与集合类完全解耦,符合单一职责原则
测试代码
@Test
public void test_book_year() { List<Book> books = new ArrayList<>(); books.add(new Book("Java编程思想", "Bruce Eckel", 2018)); books.add(new Book("Effective Java", "Joshua Bloch", 2018)); books.add(new Book("设计模式", "Erich Gamma", 1994)); books.add(new Book("鸟哥的Linux私房菜", "鸟哥", 2010)); BookAggregate bookCollection = new BookYearAggregate(books, 2018); BookIterator bookIterator = bookCollection.createIterator(); while (bookIterator.hasNext()) { Book book = bookIterator.getNext(); System.out.println(book.toString()); }
}
输出结果
Book{title='Java编程思想', author='Bruce Eckel', publishYear=2018}
Book{title='Effective Java', author='Joshua Bloch', publishYear=2018}
长话短说
迭代器模式的优势
-
解耦遍历逻辑
集合类不再关心“如何遍历”,只需提供数据。 -
支持多种遍历方式
新增迭代器即可实现新逻辑,符合开闭原则。 -
简化集合接口
集合类只需提供createIterator()
方法,接口更清晰。 -
并行遍历
可以同时创建多个迭代器,独立遍历同一集合。
何时使用迭代器模式?
- 场景特征:
-
需要以不同方式遍历集合对象(如正序、逆序、过滤)。
-
不想暴露集合的内部结构(如数组、链表等实现细节)。
-
需要为集合提供统一的遍历接口。
-