1. Apa Itu Pola Iterator

Pola iterator adalah pola desain perilaku yang menyediakan metode seragam untuk menelusuri elemen-elemen sebuah objek agregat tanpa mengekspos representasi internal dari objek agregat tersebut.

2. Karakteristik dan Keuntungan dari Pola Iterator

Karakteristik dan keuntungan dari pola iterator adalah sebagai berikut:

  • Dapat menyembunyikan struktur internal dari objek koleksi, yang memisahkan algoritma penelusuran dari objek koleksi.
  • Menyediakan cara standar untuk menelusuri berbagai jenis objek koleksi.
  • Meringankan kode klien, membuatnya lebih jelas dan ringkas.
  • Dapat menyediakan berbagai implementasi iterator untuk beradaptasi dengan berbagai kebutuhan penelusuran.

3. Contoh Aplikasi Praktis dari Pola Iterator

Pola iterator memiliki banyak aplikasi praktis, seperti:

  • Penelusuran hasil kueri basis data.
  • Penelusuran file dan folder dalam sistem file.
  • Penelusuran elemen dalam sebuah koleksi.

4. Implementasi Pola Iterator di Golang

4.1 Diagram Kelas UML

Pola Iterator di Golang

4.2 Pengantar Contoh

Dalam diagram kelas UML di atas, kita memiliki dua peran utama: Iterator dan Collection.

  • Iterator mendefinisikan antarmuka untuk menelusuri objek koleksi, termasuk metode HasNext() untuk menentukan apakah ada elemen lain dan metode Next() untuk mendapatkan elemen berikutnya.
  • ConcreteIterator adalah kelas implementasi khusus dari Iterator, yang mengimplementasikan metode HasNext() dan Next().
  • Collection mendefinisikan antarmuka untuk membuat objek iterator, dengan metode CreateIterator().
  • ConcreteCollection adalah kelas implementasi khusus dari Collection, yang mengimplementasikan metode CreateIterator().

4.3 Langkah Implementasi

Selanjutnya, kita akan mengimplementasikan pola Iterator di Golang langkah demi langkah.

4.3.1 Mendefinisikan Antarmuka Iterator dan Kelas Concrete Iterator

type Iterator interface {
    HasNext() bool
    Next() interface{}
}

type ConcreteIterator struct {
    collection *ConcreteCollection
    index      int
}

func (it *ConcreteIterator) HasNext() bool {
    if it.index < len(it.collection.items) {
        return true
    }
    return false
}

func (it *ConcreteIterator) Next() interface{} {
    if it.HasNext() {
        item := it.collection.items[it.index]
        it.index++
        return item
    }
    return nil
}

4.3.2 Mendefinisikan Antarmuka Objek Dapat Diiterasi dan Kelas Objek Dapat Diiterasi Concrete

type Collection interface {
    CreateIterator() Iterator
}

type ConcreteCollection struct {
    items []interface{}
}

func (c *ConcreteCollection) CreateIterator() Iterator {
    return &ConcreteIterator{
        collection: c,
        index:      0,
    }
}

4.3.3 Mengimplementasikan Logika Pembuatan Iterator di Kelas Objek Dapat Diiterasi

func main() {
    collection := &ConcreteCollection{
        items: []interface{}{"Golang", "Python", "Java"},
    }

    iterator := collection.CreateIterator()
    for iterator.HasNext() {
        item := iterator.Next()
        fmt.Println(item)
    }
}

Menjalankan kode di atas akan menghasilkan output berikut:

Golang
Python
Java

Pada kode di atas, kita mendefinisikan kelas ConcreteCollection yang mengimplementasikan antarmuka Collection, dengan metodenya CreateIterator() mengembalikan objek iterator. Kami menggunakan objek iterator ini dalam fungsi main() untuk penelusuran.

4.4 Perluasan Langkah Implementasi: Menyederhanakan Implementasi Iterator dengan Menggunakan Fungsi Generator

Di Golang, kita dapat menyederhanakan implementasi iterator dengan menggunakan fungsi generator (yield). Berikut adalah contoh penggunaan fungsi generator:

func GenerateItems() <-chan interface{} {
    items := []interface{}{"Golang", "Python", "Java"}

    out := make(chan interface{})
    go func() {
        defer close(out)
        for _, item := range items {
            out <- item
        }
    }()
    return out
}

func main() {
    for item := range GenerateItems() {
        fmt.Println(item)
    }
}

Pada kode di atas, kita mendefinisikan fungsi GenerateItems() yang mengembalikan channel hanya untuk dibaca (<-chan), dan menggunakan yield untuk secara berurutan mengirimkan elemen-elemen ke channel dalam fungsi ini. Pada fungsi main(), kita menggunakan range untuk menelusuri channel hanya untuk dibaca ini dan mengeluarkan nilai elemen.

Dengan cara ini, kita telah menyederhanakan implementasi iterator dengan menggunakan fungsi generator.