Bu yazıya bir renk katmak adına, biraz formal anlatım tarzı dışına çıkacağım. Neden yaptığımı merak edenler, şu araştırmaya müracaat edebilirler: https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5573739/
Bu yazı b̵i̵r̵i̵n̵c̵i̵ ikinci taslak versiyondur ve üzerinden yeniden geçilip düzeltmeler yapılacaktır. Gördüğünüz sorunları çekinmeden bildirebilirsiniz.
Öncelikle iterator pattern nedir, ona hızlıca ve çok detaylara girmeden bir bakalım. Yazılımcıların sabah akşam bazen farkına bile varmadan kullandıkları bir desen aslında. For-each her kullandığınız da iterator pattern kullanıyorsunuz. Hatta bazı diller bunu o kadar soyutluyorlar ki, bir zaman sonra o neydi diye sormaya bile başlayabilirsiniz. Ne zaman bir şeyleri iterate etmek ile alıp kullanmak istesek, List<T> gibi koleksiyon tiplerine devamlı müracaat ettiğimizden ve sonra bunları foreach döngüleri içinde iterate ettiğimizden dolayı pattern’in adı bile zamanla kafamızdan gidebiliyor.
Bu pattern’ın hayatımızın her yerinde nasıl bir yer bulabildiğini ve bu pattern’in ne olduğunu metaforlar ile açıklamadan önce, biraz terminoloji üzerinde duralım. Iterator pattern aslında iki parçadan oluşuyor. Bunlar Iterator ve Iteratable. Bu ifadelerin başka dillerde farklı söylenimleri olabiliyor: Enumerator ve Enumerable diye. Peki bunların günlük dilde kullanıldığı şekilde anlamları nedir? Matematik açısından bakıldığında bir adımı tekrar tekrar işletmek ile varılan bir miktar. Ama günlük hayatta iterate ifadesi bir şeyi tekrar tekrar işletmek. Enumerate ifadesi ise bir şeyi adım adım söylemek, saymak, vs. İngilizce bilen bir insan iseniz, o zaman iterator kelimesinin iterate işlemini yapan bir varlığa, iteratable ifadesinin de üzerinde iterate işleminin yapıldığı bir varlığa işaret ettiğini bilirsiniz.
Hayatın İçinden Iteratable Pattern
Para dolu çanta
Eğer yukarıdaki çanta kadar paranız varsa, öncelikle çıkın gidin bu yazıdan. Eğer o kadar paranız yoksa, Iterator pattern’ı anlamak kim bilir belki size o kadar para kazandırabilir. Bir gün o kadar paranız oldu ve kendinize arabaların kralı ve efendisi, eksozların amigosu, viteslerin bayrak direği, direksiyonları ağır abisi Tofaş Doğan SLX almak istediniz. Haram helal yetim hakkı demeden kazandığınız bu paradan bir miktar alıp bu galeriye vermeniz gerekiyor. Sonra aklınıza bir yazılımcı olduğunuz geldi ve atmanız gereken adımları algoritmik olarak düşünmeye başladınız: Bu çantadan para almanın yöntemi elinizi çantaya uzatmak ve oradan bir tane banknot almak, sonra onu biraz koklamak ve hayat bu işte deyip parayı bir önceki miktar ile toplamak, sonra bir tane daha banknot almak ve aynı adımları tekrarlamak. Bu adımı tekrar tekrar yapmak suretiyle Doğan SLX’i düşünerek hazzın doruklarına ulaşmak. Peki bu saçma sapan senaryoda kimin hangi rolleri olduğunu biraz inceleyelim:
Tekrar tekrar yapılan iş yani iterate işlemi: Çantaya elinizi uzatmak suretiyle bir miktar para almak.
Iterator yani iterate işlemini yapan: Siz.
Üzerinde iterate yapılan şey: Çanta.
Her bir iteration’in yapılma amacı: Para almak.
Ele geçen verinin kullanılma amacı: Galleriye para ödemek.
Yukarıda dikkat edilmesi gereken şeylerden bazıları şunlar:
Nerede kaldığınız biliyorsunuz. Dolayısıyla aynı parayı (kafanıza esip çantaya geri koyup) tekrardan çekmiyorsunuz.
Paralarının hepsini saymıyorsunuz. Sadece yeterli kadarını sayıp almaya çalışıyorsunuz. Paraların hepsini sayıp sonra içerisinden bir miktar almanın çok bir mantığı yok.
Tüm bu işlemleri bir işi tekrar tekrar yaparak işletiyorsunuz.
Başka nerede var iterator pattern?
Ne zaman yemek yapsanız, bir iterator olarak çalışıyorsunuz. Buzdolabından tereyağını, yumurtayı, sucuğu, peyniri, zeytini her aldığınız an aslında iterate işlemini yapmış olurken, siz bir iterator, ve bu durumda buzdolabı iteratable olan bir nesne olmuş oluyorlar. Iterate işlemi yapmak suretiyle elinize geçen değer buzdolabındaki gıdalar.
Konuşurken iteration yapıyorsunuz. İşte bu çok ilginç bir durum. Her bir cümlenin ağzınızdan çıkması için adım adım işletilen işlemler aynı: Ağzın açılması, beynin çalışması, nefesin çıkması, ses tellerinin titreşmesi, ve sizin hangi kelimede kaldığınızı aklınızdan saymanız (farkında olmasanız bile), cümle bitti mi bitmedimi diye takip etmeniz, cümle bitince susmanız, ya da daha önemli bir şey denilince cümlenizin hepsini bitirmek yerine kısa devre yaparak diyeceklerinizi yarıda kesmeniz. Beyniniz içinde söylemek istediğiniz düşünceler birer iteratable oluyorlar.
Çorba içerken iterator pattern. Kaşığınızı her tabağa götürmeniz bir iteration. Oradan alınan bir kaşık çorba iteration sonucunda alınan değer, onu yemeniz iteration’ın amacı, çorba tabağı iterate edilebilen şey, çorba seviyesi nerede kaldığınız gösteren bir counter, kolun ve eliniz bir iterator, siz de sabahın 3 ünde işkembeciye gitmiş bir garip.
Hatta size farklı bir düşünce katmak adına, çeşit çeşit yemekler ile döşenmiş bir sofrada yemek yemek de bir iteration. Ama yemekler farklı? Birisi peynir, birisi helva, birisi ekmek… Ama hepsi yemek. Okumadıysanız, Abstraction nedir isimli yazımı okumanızı tavsiye ederim. Yemek yerken önce helva aldıysanız, sonra peynire, sonra ekmeğe gömülmek süreti ile bir önceki adımda nerede kaldığınızı biliyor ve sonra nereye uzacağınızın farkındasınız demektir.
Yürümek bir iteration, iterasyon işlemi adımlar atarak ve nerede kaldığınızı bilerek yola devam etmek. Iterator siz, iterate edilen şey yol/mesafe. Geldiğiniz de durmak, gelmediyseniz yürümeye devam etmek de olayın check edilmesi. Matematisel ifade ile gidilmek istenilen yol miktarı iterate etmenin sonucunda varılmak istenilen değer. Yolun bitmesi de iteration işleminin bitmesinin şartı.
Gerisini siz düşünün. Bakmasını bilen bir göz iseniz, o zaman her yerde iteration göreceksiniz.
Biraz da Kodlama
Para dolu çanta örneğini basitçe kodlamaya çalıştım. Kodlama yaparken çoğu zaman her bir varlık bir sınıf ile, sahip oldukları özellikler birer property ya da field ile, yapabilecekleri ise methodlar yada fonksiyonlar ile gösterilir. Kodu okurken öncelikle Main()
fonksiyonundan başlayın, sonra parçaların detaylarına bakın. O zaman daha rahat anlarsınız. Kodu ben anlaşılır olsun diye daha genel ve sade yazdım. Iterator’un farklı implementasyon şekilleri var. Takmayın o kadar kafanıza. Mantığı anlayınca, tek farkın parçaların yerlerinin değişmesi olduğunu göreceksiniz.
class Program {
static void Main(){
Canta paraDoluCanta = new Canta();
var zengin = new Yazilimci(paraDoluCanta) { Isim="Tosun", Yas=21 }
// Zengin birisi olarak, farkli ozelliklerimi farkli siniflar ile temsil ediyorum.
// Mesela para sayma ozelligim: ParaSayar, saldiri ozelligim: HizliVeOfkeli, vs.
// GetIterator() genelde standard bir isim. Onun icin kullandim. Geriye Iterator ustipinden ParaSayar tipini gonderiyor.
ParaSaymaIterator paraSayanOzelligim = zengin.GetIterator();
double toplamPara = 0;
// paraSayanOzellik ayni zamanda Cursor olarak calisiyor. Yani bir sonraki parayi getirirken, ayni zamanda hangi parada
// kaldigimi da biliyor.
while( paraSayanOzelligim.MoveNext() ){
Para para = paraSayanOzelligim.GetCurrent();
toplamPara += para.Miktar;
// 500 Dollars bir Dogan SLX
if(toplamPara >= 500){
break;
}
}
TofasGalerisi galery = new TofasGalerisi();
Tofas doganSLX = galery.VerParayiAlKarayi(toplamPara);
doganSLX.ArabayiKullan(2, "kilometre");
// Arkadaslarin tesellisi: 500 dolara tofas almissin, 2 kilometre iyi bile gitmis
doganSLX.BakimaGotur();
}
}
class Yazilimci {
public string Isim { get;set; }
public int Yas { get;set; }
private Canta _canta;
public Yazilimci(Canta paraDoluCanta) {
_canta = paraDoluCanta;
}
public ParaSaymaIterator GetIterator(){
var ozelligim = new ParaSaymaIterator(_canta);
return ozelligim;
}
}
class ParaSaymaIterator: IterateEden {
private Para[] _toplamPara;
public Para Current {get;set;}
private int _index;
public bool MoveNext(){
if(_index >= _toplamPara.Length){
return false;
// Iflas ettim lan.
}
Current = _toplamPara[_index++];
return true;
}
public ParaSayma(Canta birCataPara){
_toplamPara = birCantaPara.ParalariVer();
}
}
class Canta: IterateEdilen {
private Para[] _paralar;
public Canta() {
_paralar = _biryerlerdenParaGetir();
}
public Para[] TumParalariVer(){
return _paralar;
}
}
class Para {
public string Birim => "USD"
public double Miktar => 100
}
Tabi böyle şeyleri basitleştirmek için, kullanılan dillerin kütüphaneleri ve framework’leri bazı interface’ler sunabiliyorlar. Amaç, çok fazla farklılık oluşturmadan senin benim de tanımladığımız iterator ve iteratable sınıfların foreach gibi döngüler ile kullanılması ve herkesin ortak anlayabileceği bir sistemin gelişmesi.
Bir sonraki yazımda görüşmek üzere.