• 微信公众号:美女很有趣。 工作之余,放松一下,关注即送10G+美女照片!

设计模式-01 迭代器模式

开发技术 开发技术 5小时前 1次浏览

设计模式-01 迭代器模式

目录
  • 设计模式-01 迭代器模式
    • 简介
    • 例子
      • 类图
      • 代码
    • 分析
      • 特点
      • 通用结构
    • 总结
      • 屏蔽实现
      • 降低耦合
      • 灵活迭代

简介

Iterator 中文对应迭代器,用于在数据集合中按照顺序遍历集合。

举一个最基本的遍历数组的例子:

public void MyStorage {
    private int[] arr;
    
    // ...
    
    public void iterateArr() {
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}

类中的 iterate 方法非常完美地解决了遍历的任务,小巧精干。

但是:

  • 它的实现决定了它只能遍历数组。
  • 暴露细节过多,如果要更改数据存储结构(arr 改成 List 类型了),则需要修改而不是添加代码,违反 OCP 原则。
  • 这个方法告诉和保证给调用者的细节过多(数据存储类型),不符合面向抽象而非具体编程的原则。
  • ……

为了解决这些问题,我们引入 Iterator 模式。

例子

类图

设计模式-01 迭代器模式

代码

public interface Aggregate {
	Iterator iterator();
}

public interface Iterator {
   boolean hasNext();
   Object next();
}

public class BookShelf implements Aggregate {

	private Book[] books;
	private int last;

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

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

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

	public int getLength() {
		return last;
	}

	@Override
	public Iterator iterator() {
		return new BookShelfIterator(this);
	}
}


public class BookShelfIterator implements Iterator {
	private BookShelf bookShelf;
	private int index;

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

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

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

public class Book {
   private String name;

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

   public String getName() {
      return name;
   }

   @Override
   public String toString() {
      return "Book{" +
            "name='" + name + ''' +
            '}';
   }
}

分析

特点

  • Aggregate 接口规定了它的实现类必须具有返回一个 Iterator 的方法,也就是说它的实现者能进行迭代。
  • Iterator 接口规定了它的实现类必须要有 next 和 hasNext 两个方法,也就是说迭代器必须要实现这两个功能。
  • BookShelfIterator 类实现了 Iterator 接口,表明它是一个迭代器,而且专门迭代 BookShelf。
  • BookShelf 类实现了 Aggregate 接口,所以它把自己作为参数,初始化返回了 BookShelfIterator 。

Client 要想遍历 BookShelf,只需要调用后者的 iterator 方法,获得 BookShef 的迭代器,然后使用迭代器进行迭代。不止对 BookShelf 这样进行迭代操作,用户对凡是实现了 Aggregate 接口的集合进行迭代,都是如此。在这个过程中:

  • 迭代的过程和具体方式对 Client 来说是未知的,非常符合面向抽象的原则。
  • 假如 BookShelf 改用 ArrayList<Book>实现书本的存储,只需要增加一个新的、实现了 Iterator 接口的迭代器,并且在这个迭代器中编写遍历 ArrayList 的具体实现,最后在 BookShelf 的 Iterator 方法中返回新的迭代器即可。因为更换数据存储结构,而对 BookShelf 产生的影响只有一行代码的修改(甚至可以直接用新的迭代器替换掉原来的 BookShelfIterator,实现 0 代码修改),符合 OCP 原则。
  • Client 完全感知不到数据存储结构和遍历实现的改变,如果在新的迭代器实现中改成逆序迭代,Client 也只会感知到迭代出的元素顺序发生了改变,完全不清楚具体的细节。

通用结构

这是更为一般的迭代器模式:

设计模式-01 迭代器模式

总结

回到一个设计模式共性的问题:为什么这么麻烦?既然是一个数组,直接遍历处理就是最好的操作,似乎根本没有引入 Iterator 的必要。

屏蔽实现

如果 BookShelf 改用 java.util.List 管理书本,Client 使用 Iterator 进行迭代的操作代码不需要任何变动:

while (iterator.hasNext()) {
	Book book = (Book) iterator.next();
    System.out.println(book.getName())
}

设计模式的作用之一就是帮助我们编写可复用的类,而所谓的可复用就是当一个组件(类)发生变化时,不需要对其他组件进行改动,或者是进行很小的改动就能应对新的变化和需求。这也进一步解释了,在 BookShelf 的 iterator 方法中返回的是一个 Iterator 而不是 BookShelfIterator。

降低耦合

以往,我们更喜欢使用具体的类来解决具体的问题,这是一种务实的做法,但具体类的编写往往会造成强的关联和耦合,设计模式的任务之一,就是要降低组件或者说代码之间的耦合。

灵活迭代

一个 ConcreteAggregate 可以对应多个 ConcreteIterator,可以从前往后迭代,也可以从后往前迭代……


程序员灯塔
转载请注明原文链接:设计模式-01 迭代器模式
喜欢 (0)