1. Iterator Pattern Nedir

Iterator pattern, bir koleksiyon nesnesinin iç temsiliyetini açığa çıkarmadan, koleksiyon nesnesinin öğelerini dolaşmanın tek tip bir yöntemini sağlayan bir davranışsal tasarım desenidir.

2. Iterator Pattern'ın Özellikleri ve Avantajları

Iterator pattern'ın özellikleri ve avantajları aşağıdaki gibidir:

  • Koleksiyon nesnesinin iç yapısını gizleyebilir, dolaşma algoritmasını koleksiyon nesnesinden ayırabilir.
  • Farklı tipte koleksiyon nesnelerini dolaşmak için standart bir yol sağlar.
  • İstemci kodunu basitleştirerek daha anlaşılır ve öz olarak yapabilir.
  • Farklı dolaşma ihtiyaçlarına uyum sağlamak için farklı iterator uygulamaları sağlayabilir.

3. Iterator Pattern'ın Pratik Uygulama Örnekleri

Iterator pattern'ın birçok pratik uygulaması vardır, örneğin:

  • Bir veritabanı sorgu sonucu kümesini dolaşmak.
  • Bir dosya sisteminde dosya ve klasörleri dolaşmak.
  • Bir koleksiyondaki öğeleri dolaşmak.

4. Golang'da Iterator Pattern'ın Uygulanması

4.1 UML Sınıf Diyagramı

Golang'da Iterator Pattern

4.2 Örnek Girişi

Yukarıdaki UML sınıf diyagramında, iki ana rolümüz var: Iterator ve Collection.

  • Iterator, bir koleksiyon nesnesini dolaşmak için arabirim tanımlar, HasNext() yöntemiyle başka bir öğe olup olmadığını belirler ve Next() yöntemiyle bir sonraki öğeyi alır.
  • ConcreteIterator, Iterator'ün özgül uygulama sınıfıdır ve HasNext() ve Next() yöntemlerini uygular.
  • Collection, iterator nesneleri oluşturmak için arabirim tanımlar, CreateIterator() yöntemiyle.
  • ConcreteCollection, Collection'ın özgül uygulama sınıfıdır ve CreateIterator() yöntemini uygular.

4.3 Uygulama Adımları

Şimdi Golang'da Iterator desenini adım adım uygulayacağız.

4.3.1 Iterator Arabirimini ve Concrete Iterator Sınıfını Tanımlama

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 Iterable Obje Arabirimini ve Concrete Iterable Obje Sınıfını Tanımlama

type Collection interface {
    CreateIterator() Iterator
}

type ConcreteCollection struct {
    items []interface{}
}

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

4.3.3 Iterable Obje Sınıfında Iterator Oluşturma Mantığını Uygulama

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

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

Yukarıdaki kod, ConcreteCollection sınıfını ve Collection arabirimini uygular ve CreateIterator() yöntemiyle bir iterator nesnesi döndürür. Bu iterator nesnesini main() fonksiyonunda dolaşım için kullanıyoruz.

Yukarıdaki kodu çalıştırdığımızda aşağıdaki çıktıyı alırız:

Golang
Python
Java

4.4 Uygulama Adımı Genişletme: Generator Fonksiyon Kullanarak Iterator Uygulamasını Basitleştirme

Go dilinde, yield (üretme) kullanarak bir generator fonksiyonunu kullanarak iterator'ın implementasyonunu basitleştirebiliriz. İşte bir generator fonksiyonunun nasıl kullanıldığına dair bir örnek:

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)
    }
}

Yukarıdaki kodda, GenerateItems() adında bir fonksiyon tanımlıyoruz ve bu fonksiyon, salt okunur bir kanal (<-chan) döndürüyor ve bu fonksiyon içinde sıralı olarak elemanları bu kanala göndermek için yield kullanıyoruz. main() fonksiyonunda ise, bu salt okunur kanalı dolaşmak ve eleman değerlerini çıktı olarak vermek için range kullanıyoruz.

Bu şekilde, bir generator fonksiyonunu kullanarak iterator'ın implementasyonunu basitleştirmiş oluyoruz.