Iterator Pattern

Паттерн Итератор для последовательного доступа к элементам коллекции без раскрытия её внутренней структуры

Паттерн Итератор (Iterator Pattern) предоставляет способ последовательного доступа к элементам коллекции без раскрытия её внутреннего представления. Итератор инкапсулирует логику обхода коллекции, что позволяет использовать единообразный способ перебора различных типов коллекций. Это упрощает работу с коллекциями и делает код более читаемым и поддерживаемым.

В примере ниже реализованы два итератора: ArrayIterator для массивов и ObjectIterator для объектов. Оба итератора предоставляют одинаковый интерфейс (next() и hasNext()), что позволяет использовать единообразный способ перебора различных типов коллекций. Итератор скрывает внутреннюю структуру данных и не позволяет напрямую изменять коллекцию во время обхода.

// Итератор для массивов
class ArrayIterator {
  constructor(collection) {
    this.collection = collection;
    this.currentIndex = 0;
  }

  next() {
    return this.collection[this.currentIndex++];
  }

  hasNext() {
    return this.currentIndex < this.collection.length;
  }

  reset() {
    this.currentIndex = 0;
  }
}

// Итератор для объектов
class ObjectIterator {
  constructor(collection) {
    this.collection = collection;
    this.keys = Object.keys(collection);
    this.currentIndex = 0;
  }

  next() {
    const key = this.keys[this.currentIndex++];
    return {
      key,
      value: this.collection[key]
    };
  }

  hasNext() {
    return this.currentIndex < this.keys.length;
  }

  reset() {
    this.currentIndex = 0;
  }
}

// Пример 1: Итерация по массиву
console.log('=== Array Iterator ===');
const arrayIterator = new ArrayIterator(['1', '2', '3', '4', '5']);

while (arrayIterator.hasNext()) {
  console.log(arrayIterator.next());
}
// Output: '1', '2', '3', '4', '5'

// Пример 2: Итерация по объекту
console.log('\n=== Object Iterator ===');
const objectIterator = new ObjectIterator({
  name: 'Kirill',
  job: 'Frontend',
  hobby: 'Coding'
});

while (objectIterator.hasNext()) {
  const item = objectIterator.next();
  console.log(`${item.key}: ${item.value}`);
}
// Output:
// name: Kirill
// job: Frontend
// hobby: Coding

// Пример 3: Универсальная функция для перебора любых коллекций
function iterateCollection(iterator) {
  const results = [];
  while (iterator.hasNext()) {
    results.push(iterator.next());
  }
  return results;
}

console.log('\n=== Universal Iteration ===');
const numbers = new ArrayIterator([10, 20, 30]);
console.log(iterateCollection(numbers)); // [10, 20, 30]

const user = new ObjectIterator({
  id: 1,
  email: 'user@example.com',
  role: 'admin'
});
console.log(iterateCollection(user));
// [{ key: 'id', value: 1 }, { key: 'email', value: 'user@example.com' }, ...]

// Пример 4: Использование reset для повторного обхода
console.log('\n=== Reset Iterator ===');
const colors = new ArrayIterator(['red', 'green', 'blue']);

console.log('First iteration:');
while (colors.hasNext()) {
  console.log(colors.next());
}

colors.reset();
console.log('Second iteration (after reset):');
while (colors.hasNext()) {
  console.log(colors.next());
}