设计模式-迭代器模式

48 阅读1分钟

定义

迭代器模式,是一种行为设计模式,它提供了一种方法顺序访问一个聚合对象中的各个元素,而又无需暴露该对象的内部表示。

迭代器模式将迭代器逻辑封装到独立的对象中,从而解耦了集合对象的遍历和业务逻辑。

UML 类图

typescript 实现

1. 迭代器接口

interface Iterator<T> {
  next(): T;
  hasNext(): boolean
}

2. 创建具体迭代器

class ConcreteIterator<T> implements Iterator<T> {
  private collection: ConcreteAggregate<T>;
  private position: number = 0;  
  constructor(collection: ConcreteAggregate<T>) {
    this.collection = collection;
  }
  public next(): T {
    const result = this.collection.getItems()[this.position];
    this.position += 1;
    return result;
  }
  public hasNext(): boolean {
    return this.position < this.collection.getSize();
  }
}

3. 定义集合接口

interface Aggregate<T> {
  createIterator(): Iterator<T>;
}

4. 创建具体集合

class ConcreteAggregate<T> implements Aggregate<T> {
  private items: T[] = [];
  public getItems(): T[] {
    return this.items;
  }
  public getSize(): number {
    return this.items.length;
  }
  public addItem(item: T): void {
    this.items.push(item);
  }
  public createIterator(): Iterator<T> {
    return new ConcreteIterator<T>(this);
  }
}

5. 使用示例

const collection = new ConcreteAggregate<string>();
collection.addItem("Item 1");
collection.addItem("Item 2");
collection.addItem("Item 3");

const iterator = collection.createIterator();

while(iterator.hasNext()) {
  console.log(iterator.next());
}

通用实现

javascript 语言层面已经有 Iterator 接口,因此无需再定义

[Symbol.iterator],这个属性会返回一个 Iterator 对象。如果实现,那么可以调用 for...of 语法

1. 类实现方式

// 公共代码
export abstract class Aggregate<T> {
  private items: T[] = [];
  protected constructor(itemOrItems?: T[] | T) {
    if(itemOritems !== undefined) {
      if(Array.isArray(itemOrItems)) {
        this.items.push(...itemOrItems);
      } else {
        this.items.push(itemOrItems);
      }
    }
  }
  public addItem(item: T): void {
    this.items.push(item);
  }
  public createIterator() {
    return new ConcreteIterator<T>(this.items);
  }
  [Symbol.iterator]() {
    return new ConcreteIterator<T>(this.items);
  }
}

export class ConcreteIterator<T> implements Iterator<T> {
  private readonly collection: T[];
  private index: number = 0;

  constructor(collection: T[]) {
    this.collection = collection;
  }
  public next(): IteratorResult<T> {
    if(this.hasNext()) {
      return { value: this.collection[this.index++], done: false };
    }
    return { value: undefined, done: true };
  }
  public hasNext(): boolean {
    return this.index < this.collection.length;
  }
}

// 私有代码,使用示例
class RangeAggregate extends Aggregate<number> {
  constructor(start: number, end: number) {
    super(Array.from( { length: end - stop }, (_, i) => i + start ));
  }
}
const range = new RangeAggregate(4, 10);
for(const num of range) {
  console.log(num); // 4,5,6,7,8,9
}

2. 函数方式

// 公共代码
export function AggregateFactory<T>(aggregate: {
  length: number,
  [key: number]: T
}, getter?: (index: number) => T) {
  return {
    index: 0,
    hasNext: function() {
      return this.index < aggregate.length;
    },
    next: function() {
      if(this.index < aggregate.length) {
        const value = getter ? getter(this.index++) : aggregate[this.index++];
        return { value, done: false };
      } else {
        return { value: undefined, done: true };
      }
    },
    [Symbol.iterator]: function() {
      this.index = 0;
      return this;
    }
  }
}

// 私有代码,使用示例
const stepRange = (start: number, stop: number, step: number = 1) => {
  const length = Math.ceil((stop - start) / step);
  return AggregateFactory(
    {
      length: length
    },
    (index) => start + index * step
  )
};

for(const num of stepRange(1, 20, 3)) {
  console.log(num); // 1, 4, 7, 10, 13, 16, 19
}