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 methodGetEnumerator()yang mengembalikan iterator. - Iterator adalah objek pembaca, misalnya class
MenuIterator. Iterator menyimpan posisi baca dan bertugas menjawabMoveNext()sertaCurrent.
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:
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:
DaftarMenu menuWarung = new DaftarMenu();
MenuIterator iterator = menuWarung.GetEnumerator();
while (iterator.MoveNext())
{
Console.WriteLine(iterator.Current);
}Output yang Dihasilkan:
Nasi Uduk
Ketoprak
Soto BetawiMari kita bedah bagian pentingnya:
_posisi = -1: iterator memulai sebelum item pertama, sehingga panggilanMoveNext()pertama berakhir tepat pada item pertama._posisi++diMoveNext(): posisi maju satu langkah, lalu method membandingkan posisi dengan panjang array untuk memutuskan apakah masih ada item.Current => _menu[_posisi]: array internal hanya disentuh oleh iterator; konsumen menerima satu item per langkah.while (iterator.MoveNext()): konsumen berhenti begituMoveNext()mengembalikanfalse; 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.