写在前面
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()
方法,接口更清晰。 -
并行遍历
可以同时创建多个迭代器,独立遍历同一集合。
何时使用迭代器模式?
- 场景特征 :
-
需要以不同方式遍历集合对象(如正序、逆序、过滤)。
-
不想暴露集合的内部结构(如数组、链表等实现细节)。
-
需要为集合提供统一的遍历接口。
-