设计模式之迭代器模式

116 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情

概念:

提供一种方法 , 顺序访问集合对象中的各个元素, 而不暴露该对象的内部表示。

优点:

  • 分离了集合对象的遍历行为
  • 抽象出了迭代器负责集合对象的遍历,可以让外部的代码透明的访问集合内部的数据

缺点:

类的个数成对增加;迭代器模式,将存储数据,遍历数据两个职责拆分;如果新添加一个集合类,需要增加该 集合类对应的迭代器类,类的个数成对增加,在一定程度上,增加了系统复杂性。

使用场景:

  • 内容保密 : 访问集合对象的内容,无需暴露内部表示
  • 统一接口 : 为遍历不同的集合结构,提供统一接口

示例代码:

题目:书(Book)放置到书架(BookSelf)中,并将书的名字按顺序显示出来

代码实现

class Book {
	constructor(name) {
		this.name = name;
	}
}

class BookSelf {
	constructor(maxSize) {
		this.books = new Array(maxSize);
		this.last = 0;
		this.maxSize = maxSize;
	}

	appendBook(book) {
		if (this.last < this.maxSize) {
			this.books[this.last] = book;
			this.last++;
		}
	}

	getLength() {
		return this.last;
	}

	getBookAt(index) {
		return this.books[index];
	}

	iterator() {
		return new MyIterator(this);
	}
}

class MyIterator {
	constructor(bookSelf) {
		this.index = 0;
		this.bookSelf = bookSelf;
	}

	next() {
		const book = this.bookSelf.getBookAt(this.index);
		this.index++;
		return book;
	}

	hasNext() {
		if (this.index < this.bookSelf.getLength()) {
			return true;
		} else {
			return false;
		}
	}
}

// 开始调用

const bookShelf = new BookSelf(4);
bookShelf.appendBook(new Book('a'));
bookShelf.appendBook(new Book('b'));
bookShelf.appendBook(new Book('c'));
bookShelf.appendBook(new Book('d'));
bookShelf.appendBook(new Book('e'));
bookShelf.appendBook(new Book('f'));
bookShelf.appendBook(new Book('g'));
bookShelf.appendBook(new Book('h'));
bookShelf.appendBook(new Book('i'));
const myIterator = bookShelf.iterator();
while (myIterator.hasNext()) {
	let book = myIterator.next();
	console.log(book, 'book');
        //Book { name: 'a' } book
        //Book { name: 'b' } book
        //Book { name: 'c' } book
        //Book { name: 'd' } book
}

类比: 由此可以类比ES6中的迭代器,见代码:

var arr = [1, 2, 3];
var nodeList = document.getElementsByClassName('test');
var map = new Map();
map.set('one', 1);
map.set('two', 2);
var set = new Set([1, 2, 3, 4]);
const each = (data) => {
	let $data = data[Symbol.iterator]();
	let item = {
		done: false,
	};

	while (!item.done) {
		item = $data.next();
		if (!item.done) {
			console.log(item, 'item');
		}
	}
};

each(arr);
//{ value: 1, done: false } item
//{ value: 2, done: false } item
//{ value: 3, done: false } item
each(nodeList);
each(map);
//{ value: [ 'one', 1 ], done: false } item
//{ value: [ 'two', 2 ], done: false } item
each(set);
//{ value: 1, done: false } item
//{ value: 2, done: false } item
//{ value: 3, done: false } item
//{ value: 4, done: false } item

类比结果:与ES6中的迭代器基本一样,最重要的就是next指针以及done属性(用来结束循环)。

总结:

自定义适配器模式灵活性更高,可以自定义遍历数据集合的顺序。