Davranışsal tasarım desenlerinden biri olan iterator pattern, bir koleksiyondaki öğeleri sırayla işlemek için bir arayüz sağlamayı amaçlar, Iterator, koleksiyondaki öğeleri tek tek döndüren bir nesnedir ve koleksiyondaki ögelerin işlemlerinin yapılmasını sağlar. Temel amacı, bir nesnenin içindeki öğelere erişimi soyutlayarak elemanların sırayla işlenmesini sağlamak ve koleksiyonun yapısından bağımsız hale getirmektir. Bu sayede koleksiyon yapısı değiştiği zaman işlev ve işlem değişmeyecektir.
Python’da Iterator patterni uygulamak için, sınıfın iter() ve next() metodlarını içermesi gerekir. iter() metodu, sınıfın bir Iterator nesnesi döndürmesini sağlar. next() metodu, bir sonraki öğeyi döndürür veya veri yapısının sonuna geldiğinde StopIteration hatası fırlatır. for döngünün çalışma prensibine benzer çalışma prensibine sahiptir. Özellikle büyük veri yapıları için oldukça kullanışlı ve verimlidir. Büyük veri yapılarına for döngüsü kullanmak, verimsiz bellek kullanımına sebep olabilir. Bu durumda, Iterator kullanarak veri yapısı üzerinde gezinmek daha verimli bir yöntemdir.
Örnek bir senaryo üzerinden kodlayarak gidersek daha iyi anlaşılacaktır. Elimizde bir müzik listesi olduğunu düşünelim ve müzik listesi elemanları arasında dolaşmak ve türlerine göre gruplamak için patterni uygulayalım.
class MusicLibraryIterator:
def __init__(self, library, grouping=None):
self.library = library
self.grouping = grouping
self.current_index = 0
self.max_index = len(self.get_songs()) - 1
def get_songs(self):
if self.grouping is None:
return self.library.songs
else:
return self.library.grouped_songs[self.grouping]
def __iter__(self):
return self
def __next__(self):
if self.current_index > self.max_index:
raise StopIteration
song = self.get_songs()[self.current_index]
self.current_index += 1
return song
class MusicLibrary:
def __init__(self):
self.songs = []
self.grouped_songs = {}
def add_song(self, song, grouping=None):
self.songs.append(song)
if grouping is not None:
if grouping not in self.grouped_songs:
self.grouped_songs[grouping] = []
self.grouped_songs[grouping].append(song)
def get_grouped_songs(self, grouping):
return self.grouped_songs[grouping]
def __iter__(self):
return MusicLibraryIterator(self)
def get_iterator(self, grouping=None):
return MusicLibraryIterator(self, grouping)
class Song:
def __init__(self, title, artist, duration, album=None):
self.title = title
self.artist = artist
self.duration = duration
self.album = album
def __str__(self):
return f"{self.title} by {self.artist} ({self.duration} seconds)"
music_library = MusicLibrary()
music_library.add_song(Song("Bohemian Rhapsody", "Queen", 354, "A Night at the Opera"), grouping="Classic Rock")
music_library.add_song(Song("Stairway to Heaven", "Led Zeppelin", 482, "Led Zeppelin IV"), grouping="Classic Rock")
music_library.add_song(Song("Hotel California", "The Eagles", 390, "Hotel California"), grouping="Classic Rock")
music_library.add_song(Song("Smells Like Teen Spirit", "Nirvana", 301, "Nevermind"), grouping="Grunge")
music_library.add_song(Song("Black Hole Sun", "Soundgarden", 335, "Superunknown"), grouping="Grunge")
for grouping in music_library.grouped_songs:
print(f"{grouping}:")
iterator = music_library.get_iterator(grouping=grouping)
for song in iterator:
print(f" {song}")
-----------------------------------------------------------------------
Output:
Classic Rock:
Bohemian Rhapsody by Queen (354 seconds)
Stairway to Heaven by Led Zeppelin (482 seconds)
Hotel California by The Eagles (390 seconds)
Grunge:
Smells Like Teen Spirit by Nirvana (301 seconds)
Black Hole Sun by Soundgarden (335 seconds)
iterator patterni uygulayarak müzik kütüphanesi üzerinde gezinmeyi kolaylaştırmış olduk, kütüphane daha karmaşık bir yapıda olsa bile iterator sayesinde kolayca dolaşılabilir oldu. Ancak unutmamak gerekirki amacı dışında veya gereksiz olarak kullanmak karmaşıklığı artıracağı gibi performansı düşmesinede yol açabilir.
Sources:
Be First to Comment