迭代器模式(Iterator Pattern)是一种行为设计模式,用于提供一种方式来顺序访问聚合对象(如数组、列表或集合)的元素,而无需暴露其底层实现。
设计模式原理
什么是迭代器模式?
迭代器模式的核心思想是将集合的遍历逻辑从集合本身分离出来,交给一个独立的迭代器对象。这样可以实现:
- 单一职责:集合负责存储数据,迭代器负责遍历逻辑。
- 灵活性:支持多种遍历方式(如正序、倒序、过滤等)。
- 封装性:隐藏集合的内部实现,客户端只需关注如何使用迭代器。
在 TypeScript 中,迭代器模式可以通过内置的 Iterable
和 Iterator
接口实现,也可以通过自定义方式实现更复杂的逻辑。
迭代器模式的结构
迭代器模式通常包含以下几个角色:
- Iterator(迭代器接口) :定义遍历元素所需的方法,如
next()
、hasNext()
。 - ConcreteIterator(具体迭代器) :实现迭代器接口,负责具体的遍历逻辑。
- Aggregate(聚合接口) :定义创建迭代器的方法,如
createIterator()
。 - ConcreteAggregate(具体聚合) :实现聚合接口,存储数据并提供迭代器。
优点
- 解耦合:将遍历逻辑与集合分离,降低耦合度。
- 多态性:支持多种遍历方式,只需实现不同的迭代器。
- 类型安全:TypeScript 的类型系统确保迭代器和集合的类型一致。
适用场景
- 需要遍历复杂数据结构(如树、图)时。
- 需要支持多种遍历方式(正序、倒序、过滤等)。
- 希望隐藏集合的内部实现细节。
TypeScript 实现示例
以下是一个使用 TypeScript 实现迭代器模式的示例。我们将创建一个书架(Bookshelf
)类,用于存储书籍,并通过迭代器遍历书籍列表。
typescript
// 迭代器接口
interface Iterator<T> {
hasNext(): boolean;
next(): T | undefined;
}
// 聚合接口
interface Aggregate {
createIterator(): Iterator<Book>;
}
// 书籍类
class Book {
constructor(private title: string) {}
getTitle(): string {
return this.title;
}
}
// 具体聚合类:书架
class Bookshelf implements Aggregate {
private books: Book[] = [];
addBook(book: Book): void {
this.books.push(book);
}
getBooks(): Book[] {
return this.books;
}
createIterator(): Iterator<Book> {
return new BookshelfIterator(this);
}
}
// 具体迭代器类
class BookshelfIterator implements Iterator<Book> {
private bookshelf: Bookshelf;
private index: number = 0;
constructor(bookshelf: Bookshelf) {
this.bookshelf = bookshelf;
}
hasNext(): boolean {
return this.index < this.bookshelf.getBooks().length;
}
next(): Book | undefined {
if (this.hasNext()) {
return this.bookshelf.getBooks()[this.index++];
}
return undefined;
}
}
// 客户端代码
function main() {
// 创建书架
const bookshelf = new Bookshelf();
bookshelf.addBook(new Book("设计模式"));
bookshelf.addBook(new Book("TypeScript 高级编程"));
bookshelf.addBook(new Book("深入理解 ES6"));
// 获取迭代器
const iterator = bookshelf.createIterator();
// 遍历书籍
while (iterator.hasNext()) {
const book = iterator.next();
if (book) {
console.log(`书籍标题: ${book.getTitle()}`);
}
}
}
main();
运行结果
运行以上代码,将输出:
makefile
书籍标题: 设计模式
书籍标题: TypeScript 高级编程
书籍标题: 深入理解 ES6
使用 TypeScript 的内置迭代器
TypeScript 提供了内置的 Iterable
和 Iterator
接口,可以简化迭代器模式的实现。例如,Bookshelf
类可以直接实现 Iterable<Book>
接口:
typescript
class Bookshelf implements Iterable<Book> {
private books: Book[] = [];
addBook(book: Book): void {
this.books.push(book);
}
[Symbol.iterator](): Iterator<Book> {
let index = 0;
const books = this.books;
return {
next(): IteratorResult<Book> {
if (index < books.length) {
return { value: books[index++], done: false };
}
return { value: undefined, done: true };
}
};
}
}
// 客户端代码
function main() {
const bookshelf = new Bookshelf();
bookshelf.addBook(new Book("设计模式"));
bookshelf.addBook(new Book("TypeScript 高级编程"));
// 使用 for...of 遍历
for (const book of bookshelf) {
console.log(`书籍标题: ${book.getTitle()}`);
}
}
main();
运行结果
makefile
书籍标题: 设计模式
书籍标题: TypeScript 高级编程
JavaScript 内部迭代器原理
JavaScript 的迭代器协议(Iteration Protocol)是 ECMAScript 2015 (ES6) 引入的核心机制,用于定义对象如何被迭代遍历。 它包括同步迭代(Iterable 和 Iterator)和异步迭代(AsyncIterable 和 AsyncIterator),允许开发者自定义遍历行为。
同步迭代协议
Iterable 接口
任何对象如果实现了 Symbol.iterator
方法,则被视为可迭代对象。该方法返回一个符合 Iterator 协议的对象。当引擎遇到需要迭代的对象时(如 for...of
),它会调用 [Symbol.iterator]()
获取迭代器。
Iterator 接口
迭代器对象必须实现 next()
方法,返回 { value: any, done: boolean }
。done
为 true 表示迭代结束。迭代器维护内部状态,每次 next()
调用推进状态。
语言集成
- for...of :调用
[Symbol.iterator]()
,循环next()
,如果提前退出,调用return()
清理资源。 - 其他:Spread 操作符、
Array.from()
、解构赋值。 - 内置对象:Array、Map、Set、String 等实现该协议.
生成器(function*
和 yield
)是迭代器的语法糖,返回 Generator 对象,既是 iterable 又是 iterator。
异步迭代协议
AsyncIterable 和 AsyncIterator
Symbol.asyncIterator
:返回 AsyncIterator。next()
:返回Promise<IteratorResult>
。- for-await-of :异步版本的
for...of
.
这适用于处理 Promise 或异步序列,如网络响应。
使用 Node.js 实现一个类似 Deno.serve 的方法
在 Web 服务器中,异步迭代器特别适合处理异步网络请求,例如逐个处理 incoming requests 或以流式方式发送响应数据,避免一次性加载整个数据到内存。基于对 Deno.serve 的分析(其利用 Deno.Listener
和 Deno.HttpConn
的 AsyncIterable 特性迭代连接和请求),我们实现一个 Node.js 版本的 serve
函数,类似于 Deno.serve,支持异步处理函数,并通过异步迭代器处理请求流和响应流。
实现示例
以下是一个精简的 Node.js HTTP 服务器实现,使用 TypeScript 和 async *
语法糖,隐藏显式 AsyncIterator 概念,清晰展示请求流到响应流的转换。
typescript
import { createServer, IncomingMessage, ServerResponse } from 'http';
import { Readable } from 'stream';
// 自定义响应类型(类似于 Deno 的 Response)
type Handler = (req: IncomingMessage) => Promise<ResponseLike>;
interface ResponseLike {
status?: number;
headers?: Record<string, string>;
body: string | Buffer | Readable | AsyncIterable<Buffer | string>;
}
// 将 request 事件转为 AsyncIterable
async function* listen(server: ReturnType<typeof createServer>) {
const q: [IncomingMessage, ServerResponse][] = [];
server.on('request', (req, res) => q.push([req, res]));
while (true) {
while (q.length) yield q.shift()!; // 先消化积压
await new Promise(r => server.once('request', r)); // 再等下一个
}
}
// 自定义 serve 函数,使用异步迭代处理请求
export async function serve(handler: Handler, port = 3000) {
const server = createServer(); // 不挂任何回调,完全由我们控制
server.listen(port, () => console.log(`http://localhost:${port}`));
for await (const [req, res] of listen(server)) {
try {
const { status = 200, headers = {}, body } = await handler(req);
res.writeHead(status, headers);
if (Symbol.asyncIterator in body) {
Readable.from(body as AsyncIterable<any>).pipe(res); // 流式输出
} else {
res.end(body); // 一次性输出
}
} catch {
res.writeHead(500).end('Internal Server Error');
}
}
}
// 示例使用:异步 handler 处理请求
if (require.main === module) {
serve(async req => {
const { pathname } = new URL(req.url!, `http://${req.headers.host}`);
if (pathname === '/stream') {
async function* counter() {
for (let i = 0; i < 5; i++) {
await new Promise(r => setTimeout(r, 1000));
yield `chunk ${i}\n`;
}
}
return { body: counter(), headers: { 'content-type': 'text/plain' } };
}
return { body: 'Hello World' };
});
}
运行与测试
-
运行:
npx tsx server.ts
(或使用 ts-node)。 -
访问:
http://localhost:3000/stream
,浏览器或 curl 将逐秒接收 "chunk" 数据。 -
输出示例:
bashhttp://localhost:3000 [访问 /stream,每秒输出一行:] chunk 0 chunk 1 chunk 2 chunk 3 chunk 4
总结
迭代器模式通过分离遍历逻辑,提供灵活的集合访问方式。JavaScript 的迭代器协议为其提供了底层支持,而异步迭代器进一步扩展到异步场景,如 Node.js 的自定义 serve
示例。通过 async *
和 Readable.from
,请求流和响应流清晰转换,实现了类似 Deno.serve 的简洁 API。这展示了迭代器模式在现代 Web 开发中的强大应用。