Iterator Pattern Nedir? Nasıl Kullanılır?

Yazılım geliştirirken, koleksiyonlar üzerinde gezinmek çoğu zaman temel bir ihtiyaç hâline gelir. Bu ihtiyaca yönelik en yaygın çözümlerden biri, Iterator patterndir. Bu deseni kullanarak koleksiyonların içeriğini tek tek dolaşırım ve veri yapısının iç detaylarına bağlı kalmadan elemanlara doğrudan erişirim.

Iterator Pattern, Davranışsal (Behavioral) tasarım desenleri arasında yer alır. Temel amacı, bir koleksiyonun içindeki nesneler üzerinde sırayla dolaşmayı sağlar ve bunu yaparken koleksiyonun nasıl yapılandığıyla ilgilenmem gerekmez. Bu sayede kod daha esnek ve sürdürülebilir hâle gelecektir.

Java, bu deseni standart kütüphanelerinde başarıyla uygular. java.util.Iterator arayüzü, bu desenin doğrudan bir yansımasıdır. Koleksiyon sınıfları (ArrayList, HashSet gibi), bu arayüzü destekleyerek elemanları güvenli ve temiz bir şekilde dolaşmama olanak tanır.

iterator-pattern-uml
Image Created by ChatGPT

Iterator Pattern’ın Bileşenleri

Iterator Pattern genellikle şu dört bileşeni içerir:

  1. Iterator ArayüzühasNext(), next() gibi gezinme yöntemlerini tanımlar.
  2. Concrete Iterator (Somut Yineleyici) – Belirli bir koleksiyon türü için Iterator arayüzünü uygular.
  3. Aggregate Arayüzü – Koleksiyonun Iterator nesnesi üretmesini sağlar.
  4. Concrete Aggregate (Somut Koleksiyon) – Koleksiyonu tutar ve Iterator döner.

Kendi koleksiyon sınıfımı oluşturduğumda, onun üzerinde gezinmek için de kendi yineleyicimi yazabilirim. Şimdi bu yapıyı örnek bir senaryo ile inceleyelim.

Kullanım Örneği

// Koleksiyonum
class Kitap {
    String isim;
    public Kitap(String isim) {
        this.isim = isim;
    }
    public String getIsim() {
        return isim;
    }
}

// Iterator Arayüzü
interface KitapIterator {
    boolean hasNext();
    Kitap next();
}

// Concrete Iterator
class KitapListesiIterator implements KitapIterator {
    private Kitap[] kitaplar;
    private int pozisyon = 0;

    public KitapListesiIterator(Kitap[] kitaplar) {
        this.kitaplar = kitaplar;
    }

    public boolean hasNext() {
        return pozisyon < kitaplar.length;
    }

    public Kitap next() {
        return kitaplar[pozisyon++];
    }
}

// Concrete Aggregate
class KitapListesi {
    private Kitap[] kitaplar;
    
    public KitapListesi() {
        kitaplar = new Kitap[] {
            new Kitap("Design Patterns"),
            new Kitap("Clean Code"),
            new Kitap("Effective Java")
        };
    }

    public KitapIterator iterator() {
        return new KitapListesiIterator(kitaplar);
    }
}

public class Main {
    public static void main(String[] args) {
        KitapListesi liste = new KitapListesi();
        KitapIterator iterator = liste.iterator();

        while (iterator.hasNext()) {
            Kitap kitap = iterator.next();
            System.out.println(kitap.getIsim());
        }
    }
}

Iterator Tasarım Deseninin Avantajları

  1. Soyutlama Sağlar: Koleksiyonun iç yapısını bilmeden onun üzerinde gezinmeme olanak tanır. Örneğin, bir ArrayList mi yoksa HashSet mi olduğunu önemsemeden her bir elemanı sırayla alabilirim.
  2. Tek Sorumluluk İlkesine Uyar: Koleksiyonun veri tutma sorumluluğu ile gezinme sorumluluğunu birbirinden ayırır. Koleksiyon sadece veriyi saklar, iterator ise bu verinin üzerinde gezinmeyi üstlenir.
  3. Kod Tekrarını Azaltır: Farklı koleksiyon türleri için aynı gezinme mantığını kullanmamı sağlar. Bu da kodun yeniden kullanılabilirliğini artırır.
  4. Genişletilebilirlik Sunar: Yeni koleksiyon türleri eklediğimde sadece ona özel bir iterator yazmam yeterli olur. Mevcut yapıları değiştirmeme gerek kalmaz.
  5. Güvenli Gezinme: Iterator nesnesi, koleksiyonun yapısını dışarıdan değiştirmeden dolaşmaya olanak tanır. Böylece veri bütünlüğü korunur.

Iterator Design Pattern Dezavantajları

  1. Ekstra Sınıflar ve Karmaşıklık: Küçük projelerde her koleksiyon için özel bir iterator sınıfı yazmak gereksiz karmaşıklık yaratabilir.
  2. Geriye Doğru Gezinme Zorluğu: Standart Iterator arayüzü ileriye doğru gezinmeyi destekler. Geriye doğru gitmek için ListIterator gibi özel arayüzlere ihtiyaç duyarım.
  3. Eşzamanlılık Sorunları: Koleksiyon üzerinde gezinirken başka bir işlem koleksiyonu değiştirirse ConcurrentModificationException hatası alabilirim. Bunu önlemek için eşzamanlı koleksiyon yapıları ya da CopyOnWriteArrayList gibi alternatifler kullanmalıyım.

Nerelerde Kullanabiliriz?

  1. Özel Koleksiyon Yapıları: Kendi veri yapılarımı yazdığımda (örneğin, bir ağaç, grafik ya da dairesel liste gibi), bu yapıların üzerinde standart bir şekilde gezinmek için iterator kullanırım.
  2. API Tasarımları: Kütüphane geliştirirken, kullanıcıların koleksiyonlarım üzerinde rahatça gezinebilmelerini sağlamak için bu deseni uygularım.
  3. Veri Akışı Senaryoları: Büyük veri setleri üzerinde satır satır işlem yaparken her veriyi belleğe almadan iterator ile işlem yaparım.
  4. Yaygın Koleksiyon Kullanımı: for-each döngüsünün Java’da çalışmasını sağlayan mekanizma da aslında Iterator arayüzüne dayanır. Örneğin:
for (String isim : isimListesi) {
    System.out.println(isim);
}

Bu kullanımın arka planında Iterator çalışır.

Sonuç

Iterator Pattern, karmaşık veri yapılarında gezinmemi sağlar ve koleksiyonun iç yapısına müdahale etmeden bu işlemi gerçekleştirmeme olanak tanır. Bu desen, özellikle kendi özel koleksiyon sınıflarımı oluşturduğumda veya var olan yapılar üzerinde soyutlama sağlamak istediğimde bana büyük kolaylık sunar. Kodun okunabilirliğini artırır, bakımını kolaylaştırır ve yazılımın esnekliğini önemli ölçüde yükseltir.

Iterator Pattern, yazılımda gezinme sorumluluğunu soyutlayarak koleksiyonlar üzerinde daha okunabilir, güvenli ve sürdürülebilir kod yazmamı sağlar. Büyük ölçekli projelerde, koleksiyonlar büyüyüp çeşitlendikçe bu desenin değeri daha da artar. Ancak küçük ve basit uygulamalarda, gereksiz karmaşaya neden olmamak için dikkatli kullanılmalıdır.

Kod yapısını temiz tutmak, sorumlulukları ayırmak ve esnek sistemler kurmak istiyorsan, Iterator Pattern’ı mutlaka araç kutunda bulundurmalısın.

Paylaşmak ister misin?

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir