8 Şubat 2011 Salı

Nesne Yönelimli Programlama – 3 Constructor kavramı ve Class tasarımı

Bu makalemize bir soru ile başlayalım; nasıl oluyor da bir class' tan bir nesne türetebiliyoruz? Bu "türetme" işine kod tarafında baktığımızda en sık karşılaştığımız yöntem, "new" anahtar kelimesi kullanmaktır. Örneğin;
Ayakkabi pabuc = new Ayakkabi();
Örnekteki "new Ayakkabi()" kısmı, Ayakkabi class'ı içinde bulunan tüm üyeleri, pabuc isimli nesneye aktarır. Biz bu duruma Ayakkabi class'ından nesne türetmek ya da daha teknik bir ifadeyle instance almak diyoruz. Şimdi, işi biraz daha basit almak istiyorum. Aslında, nesne üretmenizi sağlayan şey class' ınızın içinde bulunan oluşturucu metot (constructor) dediğimiz üyedir.
Constructor, kesinlikle bir metottur. Ama herhangi bir değer döndüren metot değildir. Ya da void metot olarak da düşünülemez. Constructor, yalnızca üyesi bulunduğu class'dan nesne üretimi sırasında çalışacak olan metoddur. Bu durumda şunu söylemek çok yanlış olmayacaktır, classımdan nesne üretilirken; üyelerin varsayılan değerlerini ayarlamak için constructor kullanırım. Bakınız, Windows uygulaması geliştirirken hep gözümüzün önünde bulunan bir constructor'u inceleyelim şimdi…
Bildiğiniz gibi Windows Form'u aslında bir class. Bakalım bu class' ın bir constructor'u var mı?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
}
İşte orada! public Form1() ifadesi ile başlayan üye bizim constructor' ımız oluyor. Şimdi gelin bu tanımı biraz inceleyelim. Gördüğünüz gibi constructor' un erişim düzenleyicisi (Access Modifier) public. Çoğu constructor'un erişim düzenleyicisi public' tir. Bunun sebebi, elbette constructor'a class dışından erişilebilir olması gerektiğidir. ( Aksi halde, Form1 frm = new Form1 (); diye bir ifade yazamazdık.) Constructor tanımının bir diğer özelliği ise isminin class ismiyle aynı olmasıdır (Form1()). İşte object oriented modellemenin vaz geçilmezi constructor ile böylece tanışmış olduk.
Şimdi, aklınıza bir sorunun takıldığını hissediyorum. Şöyle ki, "geçtiğimiz OOP makalelerinde yazdığımız Ayakkabi class' ında constructor yazmadığımız halde pabuc nesnesini türetebilmiştik bu nasıl oldu?" Hemen cevaplayalım; Yazdığınız her class'ta varsayılan olarak bir constructor bulunur. Dolayısıyla, siz yalnızca varsayılan ayarları değiştirmek için constructor tanımlarsınız. Belki bu cevap kafanızda bir soru daha oluşmasına neden olacaktır; 'madem varsayılan olarak bir constructor zaten var o halde neden Form1 classı bir constructor içeriyor? ' bunun da cevabını hemen verelim; yukardaki örneğe dikkat ederseniz Form1() constructor'u içerisinde çağırılan InitializeComponent(); isimli bir metot var. Bu metot, Form1.Designer.cs dosyasında bulunan bir metottur ve görevi form üzerinde kullandığımız kontrolleri ve bu kontrollerin özelliklerini oluşturmaktır.
Şunu tekrar belirtelim; constructor, classdan instance alınırken çalışır ve amacı, class üyelerinizin değerlerini ayarlayak nesne referansına geçirir.
Şimdi gelin, bizim meşhur Ayakkabi class'ımıza bir constructor ekleyelim. Hemen kafamızda bir senaryo oluşturalım. Bir ayakkabıcıya gittiniz. Doğru ayakkabıyı alabilmek için, ayakabbıcının bilmesi gereken şey, kaç numara giydiğinizdir öyle değil mi? Sizin elde edeceğiniz ayakkabı nesnesi belirttiğiniz ayak numarasına bağlıdır öncelikle. Madem öyle, işte Ayakkabi class'ımızın constructor'u geliyor:
public Ayakkabi(byte ayakkabiNo)
{
numarasi = ayakkabiNo;
}
Ne mi yaptık? Artık Ayakkabi class'ından nesne üretirken sizden ayakkabiNo parametresinin değerini alacak. Ardından bu değeri class üyelerinden "numarasi" isimli alana (bkz. OOP2 Encapsulation) aktaracak. Böylece "Numarasi" özelliğinin değeri oluşmuş olacak. Haydi... Nesneyi üretirken görelim: 


private void Form1_Load(object sender, EventArgs e)
{
Ayakkabi pabuc = new Ayakkabi(44);
}
Görüldüğü gibi pabuc nesnemi üretirken artık numara parametresini girme zorunluluğum var. Şunu da belirtelim ki, constructor'un bir nevi metod olduğunu unutmayın. Bu demek oluyor ki, constructor'lar da overload edilebilirler.
Buradan anlaşılıyor ki, constructor yapısı class tasarımı için vazgeçilmez bir kavram. Aslında söz class tasarımına geldiğinde göre, biraz da bu konu üzerinde duralım.
Class tasarımı dediğimizde, o classı oluşturan üyelerin neler olacağı ve nasıl çalışacağı üzerinde kafa patlatmaktan bahsediyoruz. Doğru tasarlanmış bir class, programcıya çok daha yardımcı olacaktır. Tasarıma ilk olarak, özelliklere ve bu özelliklerin tiplerine karar vererek başlarsınız. Bir özelliğe karar verirken ele aldığınız kriter ilk olarak o özellikle ne yapacağınızdır. Örneğin bizim class'ımızda malzemesi, markasi ve tipi özellikleri arama yapmak için kullanılabilir mi? Evet kullanılabilir. O halde bu özelliklerin tipleri ne olmalıdır? Aklınıza "string" geldiğini hisseder gibiyim. O zaman izninizle biraz kafanızı karıştırmak istiyorum.
Markasi özelliğinin tipini "string" yapmaya karar verdiniz. Sonra kodlama aşamasına geçtiniz ve "Adidas", "Nike" ile "Camel" markalarından olmak üzere üç farklı nesne ürettiniz. Buraya kadar tamam. Şimdi de bir MarkayaGoreAra metodu yazdınız ve doğal olarak parametresi de string tipinde. Bu metodu test ediyorsunuz; MarkayaGoreAra("adidas"); yazdığınızda sonuç bulunur mu? Efendim? Bulunur mu dediniz? Üzgünüm yanlış cevap. Sonuç bulunamaz. Ben "Adidas" markalı bir ayakkabı oluşturdum, "adidas" değil. Unutmayın.. case sensitivity öldürür!!
Peki o zaman ne yapacağız? Markasi özelliğinin tipi string olmazsa ne olacak? Acaba kendi tipimizi yapsak nasıl olur? Öyle bir tip yazalım ki, sattığımız ayakkabi markalarını üye olarak içersin. Bu cümleyi okuyan bazı arkadaşlarım enum'dan bahsettiğimi hemen anlayacaklardır. Eğer, belli değerler arasında sınırları olan (Örneğimizde; yalnızca "Adidas", "Nike" ile "Camel" markaları seçilebilecektir.) tipler oluşturmak istiyorsak enum olarak isimlendirdiğimiz yapıları kullanıyoruz. Hemen bunu örneğimiz üzerinde uygulayarak görelim.
Projemize sağ click / Add / Class diyelim ve "Enums" isimli bir fiziksel dosya ekleyelim. Ardından açılan dosyada namespace alanı içindeki tüm kodları temizleyelim... Ops! Bunu neden mi yaptık? Elbette oluşturacağımız enum tipini farklı fiziksel dosyada tutmak için... Şimdi buraya enum tipimizi yazalım:
public enum MarkaIsimleri
{
Adidas,
Nike,
Camel
}
İşte kendi value-type' ımızı oluşturduk. Şimdi Ayakkabi class'ı içinde bulunan Markasi özelliğini kendi tipimizle tekrar oluşturalım:
public MarkaIsimleri Markasi { get; set; }
Böylece artık Markasi özelliğine değer aktarırken, belirttiğimiz alanlardan değer seçme özgürlüğüne sahip olacağız. Haydi bunun da fotoğrafını çekelim: 


Ya arkadaş, bir programcı daha ne ister? Resmen MarkaIsimleri tipim beni yönlendiriyor: "kardeşim senin sattığın markalar bunlar, seç birini". Şimdi yukarıda oluşturduğumuz ayyakkabı arama senaryosuna geri dönelim. Artık MarkayaGoreAra metodunuzun parametresi string değil MarkaIsimleri tipinde olacaktır ve doğal olarak siz bu metodu şöyle çağırabileceksiniz; MarkayaGoreAra(MarkaIsimleri.Adidas); . Bakınız güzel bir class tasarlayarak, kendinize iyilik yaptınız. Şimdi class' imizdaki diğer bazı özellikler için de birer enum yazalım ve ardından Markasi özelliğinde yaptığımız gibi, söz konusu özellikleri yeniden oluşturalım.
Enums.cs :
public enum AyakkabiTipleri
{
Bot,
Çizme,
SporAyakkabi,
Sandalet
}
public enum MalzemeTipleri
{
Nubuk,
Deri,
Suet
}
Ayakkabi.cs:
public AyakkabiTipleri AyakkabiTipi { get; set; }
public MalzemeTipleri Malzemesi { get; set; }
Böylece, basitçe class modelleme konusuna değinmiş olduk. Modelleme konusu elbette bu kadarla sınırlı kalmıyor. Ama konuyu başka makalelere bırakıyorum.
Burada isterseniz constructor konusuna geri dönelim... En son, constructor yapısının da overload edilebileceğini belirtmiştim. O zaman yapalım!
Bir müşteri ayakkabıcıya girdiğinde, "42 numara spor ayakkabı istiyorum" ya da "42 numara deri çizme istiyorum" diyebilir değil mi? İşte bu parametreleri değerlendirerek Ayakkabi class'inin constructor metodunu overload edelim.
public Ayakkabi(byte ayakkabiNo, MarkaIsimleri marka)
{
numarasi = ayakkabiNo;
Markasi = marka;
}
public Ayakkabi(byte ayakkabiNo, MarkaIsimleri marka, MalzemeTipleri malzeme)
{
numarasi = ayakkabiNo;
Markasi = marka;
Malzemesi = malzeme;
}
Eh artık bunun da fotoğrafını çekmek bir zaruret: 




Yazar:Türkay Ürkmez
Kaynak:turkayurkmez.com

Hiç yorum yok:

Yorum Gönder