Bayangkan sebuah warung menyimpan menu pada array internal, tetapi pemilik tidak ingin pembeli tahu bagaimana data disimpan dan mungkin nanti berganti ke List atau database. Kebutuhan seperti inilah yang dijawab iterator pattern: pola desain klasik yang memberi akses berurutan ke isi koleksi tanpa membuka struktur internalnya. .NET menanamkan pola ini langsung ke bahasa lewat pasangan IEnumerable dan IEnumerator, sehingga kita tidak memerlukan framework tambahan untuk menerapkannya.

Dua Peran dalam Pola Iterator #

Pola ini melibatkan dua objek yang bekerja sama:

  • Aggregate adalah koleksinya sendiri, misalnya class DaftarMenu. Aggregate menyimpan data dan menyediakan method GetEnumerator() yang mengembalikan iterator.
  • Iterator adalah objek pembaca, misalnya class MenuIterator. Iterator menyimpan posisi baca dan bertugas menjawab MoveNext() serta Current.

Pemisahan ini membuat satu koleksi bisa punya banyak pembaca aktif sekaligus; setiap pembaca membawa posisi masing-masing, dan koleksi tidak ikut berubah saat pembacaan berlangsung.

Implementasi Manual pada Koleksi Khusus #

Contoh berikut menerapkan kedua peran tanpa bantuan yield, agar mekanismenya terlihat jelas:

csharp
public class DaftarMenu
{
    private readonly string[] _menu =
    {
        "Nasi Uduk",
        "Ketoprak",
        "Soto Betawi"
    };

    public MenuIterator GetEnumerator()
    {
        return new MenuIterator(_menu);
    }
}

public class MenuIterator
{
    private readonly string[] _menu;
    private int _posisi = -1;

    public MenuIterator(string[] menu)
    {
        _menu = menu;
    }

    public bool MoveNext()
    {
        _posisi++;
        return _posisi < _menu.Length;
    }

    public string Current => _menu[_posisi];
}

Kode konsumen hanya menyentuh iterator, tidak pernah menyentuh array internal:

csharp
DaftarMenu menuWarung = new DaftarMenu();

MenuIterator iterator = menuWarung.GetEnumerator();
while (iterator.MoveNext())
{
    Console.WriteLine(iterator.Current);
}

Output yang Dihasilkan:

text
Nasi Uduk
Ketoprak
Soto Betawi

Mari kita bedah bagian pentingnya:

  1. _posisi = -1: iterator memulai sebelum item pertama, sehingga panggilan MoveNext() pertama berakhir tepat pada item pertama.
  2. _posisi++ di MoveNext(): posisi maju satu langkah, lalu method membandingkan posisi dengan panjang array untuk memutuskan apakah masih ada item.
  3. Current => _menu[_posisi]: array internal hanya disentuh oleh iterator; konsumen menerima satu item per langkah.
  4. while (iterator.MoveNext()): konsumen berhenti begitu MoveNext() mengembalikan false; isi array dan cara penyimpanannya tetap tersembunyi.

Menulis iterator manual seperti ini sah, tetapi panjang untuk kebutuhan sehari-hari. Bab berikutnya memperkenalkan yield return, kata kunci yang menyuruh compiler membangun iterator tersebut untuk kita.