Перейти к содержанию

Iterator.cs

Код подключён напрямую из исходного файла в кодировке UTF-8, поэтому эта страница всегда показывает его актуальную версию.

← К конспекту Скачать исходный файл

Iterator.cs
using System;
using System.Collections;
using System.Collections.Generic;

namespace DesignPatterns.Behavioral.Iterator
{
    // Собственная коллекция со скрытой внутренней структурой (кольцевой буфер).
    // Реализуя IEnumerable<T>, мы даём клиенту единый способ обхода (foreach),
    // не раскрывая, что внутри на самом деле массив фиксированного размера с "головой" и "хвостом".
    public sealed class RingBuffer<T> : IEnumerable<T>
    {
        private readonly T[] _items;
        private int _head;
        private int _count;

        public RingBuffer(int capacity)
        {
            _items = new T[capacity];
        }

        public void Add(T item)
        {
            int index = (_head + _count) % _items.Length;
            _items[index] = item;

            if (_count < _items.Length)
            {
                _count++;
            }
            else
            {
                _head = (_head + 1) % _items.Length; // самый старый элемент затирается
            }
        }

        // Благодаря yield return компилятор сам генерирует класс-итератор,
        // реализующий IEnumerator<T> - вручную его писать не нужно.
        public IEnumerator<T> GetEnumerator()
        {
            for (int i = 0; i < _count; i++)
            {
                int index = (_head + i) % _items.Length;
                yield return _items[index];
            }
        }

        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    }

    public static class Demo
    {
        public static void Run()
        {
            var buffer = new RingBuffer<int>(capacity: 3);
            buffer.Add(1);
            buffer.Add(2);
            buffer.Add(3);
            buffer.Add(4); // 1 будет вытеснен

            // Клиентский код использует обычный foreach и ничего не знает
            // про кольцевой буфер, "голову" и "хвост" внутри.
            foreach (int item in buffer)
            {
                Console.WriteLine(item);
            }
        }
    }
}