Sınıf, Nesne, Constructor, Destructor, Abstraction ve Encapsulation, Property
1960’lı yıllarının sonuna doğru kodlama karmaşıklığı ve kod uzunluğu sürekli artmaktaydı. Bu durum kodların iyileştirilmesini, hata ayıklamayı ve takım çalışmasını zorlaştırmaktaydı. Yazılım ortamı geliştiricileri bu zorlukları ortadan kaldırmak için gerçek hayatı göz önüne alıp modellenmesine olanak sağlayan Nesneye Yönelimli Yaklaşımını önermişlerdir. Günümüzdeki Java, C++ ve C# gibi başlıca programlama dillerinin hepsi bu yaklaşım üzerine inşa edilmiştir. Bu yazımda gerçek dünyadan bir modellemenin nasıl yapıldığını temel özellikler üzerinden anlatmayı ve bu modellemenin kod tarafına aktarılmasını anlatacağım.
Sınıf vs. Nesne (Class vs. Object)
Sınıf deyince öğrencilerimin bazıları eğitim yılları, bazıları Darwin’in canlı sınıfları, bazılarının siyasi tarafı gelmektedir. Öncelikle belirtmeliyim ki biz sınıflara bölmekle uğraşan kişiler değiliz. Eğer sınıflara bölen kişiler olsaydık bizim yan bir dünyamız olan elektronik dünyası halen mevcut transistörleri sınıflama çalışırdı. Oysa ki elektronik dünyası mevcut durumları geliştirip yeni transistör yapabilmiştir. (Kaynaklar bölümündeki makaleyi öneririm.) Bizim bu dersteki amacımız kendi sınıflarımızı en iyi şekilde modellemek olacaktır. Bu günkü örneğin çocukluk yıllarımın rüyası olan futbol konusu olacak ve bir futbol oyununun temelini atacağız.
Bir sınıfta modele ait değişken ve metotlar (fonksiyon veya yordam) bulunduran temel bileşenimizdir. Bu bileşen üzerinden nesnelerimizi yaratıp, nesneler üzerinden değişken ve fonksiyonlarımıza ulaşabiliriz. Kısacası, Futbolcu bir sınıf iken Messi, Quresma, Ronaldo nesnelerimiz olacaktır. Öncelikle, her nesnenin ortak özelliklerini belirleyelim.
Sınıfımız bir ad değişkenin yanı sıra çalım, hız, şut, yetenek, defans, kafa, pas vb. bir çok özelliğimiz olabilir. Ad değişkeni nesne oluşturduğumuzda nesnenin diğer nesnelerden ayırt edilmesini sağlar. Diğer özellikler futbolcunun özelliklerini belirleyen değişkenlerdir. Bu değişkenler hesaplanabilirlik kavramına (Alan Turing ve Turing tezini araştırabilirsiniz) uygun olması için sayısal değerler olabilir. Şimdi bu modelimizi koda dökelim.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class Futbolcu { public string ad_soyad; public int calim; public int hiz; public int sut; //bir çok özellik olabilir. public void adam_gec(){ /*Adam geçme olasılığı, yukarıdaki değer, karşı oyuncunu yetenekleri ve random bir fonksiyon yazılıp yapılabilir. Bu fonksiyon kalitesi oyunun gerçekliğini belirler.*/ } public void gol_dene(){ /*Oyuncunun şut özelliği, kalecinin yeteneği, vuruşun mesafesi vb. durumları göz önüne alıp gol olup olmayacağını belirleyen fonksiyon. */ } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class FutbolOyunu { public static void Main() { Futbolcu _f1 = new Futbolcu(); _f1.ad_soyad = "Lionel Messi"; _f1.calim = 94; _f1.hiz = 84; //diğer özellikler eklenebilir. Futbolcu _f2 = new Futbolcu(); _f2.ad_soyad = "Cristiano Ronaldo"; _f2.calim = 90; _f2.hiz = 92; //diğer özellikler eklenebilir. } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class Futbolcu { public string ad_soyad; public int calim; public int hiz; public int sut; //bir çok özellik olabilir. public Futbolcu(string _ad_soyad, int _calim, int _hiz, int _sut) { ad_soyad = _ad_soyad; calim = _calim; hiz = _hiz; sut = _sut; } ... } |
1 2 3 4 5 6 7 8 |
public class FutbolOyunu { public static void Main() { Futbolcu _f1 = new Futbolcu("Lionel Messi", 94, 84, 89); Futbolcu _f2 = new Futbolcu("Cristiano Ronaldo", 90, 92, 95); } } |
Görüldüğü gibi ilk yaratma anında özelliklerimizi belirledik. Kod kısmı sınıf içine taşındı ve main kısmındaki kod azaldı. Ayrıca main kısmında özellik unutulması durumunda IDE’miz bizi uyaracaktır. Bu tür hataları da önlemiş olacağız.
Destructor (Yıkıcı)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public class Futbolcu { public string ad_soyad; public int calim; public int hiz; public int sut; //Yapıcı public Futbolcu(string _ad_soyad, int _calim, int _hiz, int _sut) { ad_soyad = _ad_soyad; calim = _calim; hiz = _hiz; sut = _sut; } //Yıkıcı ~Futbolcu() { /*... Çeşitli işlemler yapılabilir. Örneğin Messi maçta 3 gol atmış Şut özelliğini 1 arttır, dosyaya veya veritabanına kaydet.*/ GC.Collect(); /* GC(Garbage collector)'in zorunlu olarak bellekteki gereksiz objeleri kaldırması istenebilir.*/ } ... } |
Abstraction (Soyutlama) ve Encapsulation (Saklama, Paketleme)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class Futbolcu { private string ad_soyad; private int calim; private int hiz; private int sut; //bir çok özellik olabilir. public Futbolcu(string _ad_soyad, int _calim, int _hiz, int _sut) { ad_soyad = _ad_soyad; calim = _calim; hiz = _hiz; sut = _sut; } ... } |
1 2 3 4 5 6 7 8 9 |
public class FutbolOyunu { public static void Main() { Futbolcu _f1 = new Futbolcu("Lionel Messi", 94, 84, 89); //_f1.calim = 96; //Bu kısım artık çalışmaz, ulaşılamaz. Ama sınıf içinden bu kısma ulaşılabilir. Futbolcu _f2 = new Futbolcu("Cristiano Ronaldo", 90, 92, 95); } } |
Bir kaç çözüm şansınız var.
Birinci çözüm yönteminde yapıcı içine if şartımızı yazabiliriz.
12345678910111213 public class Futbolcu{private int hiz;...public Futbolcu(..., int _hiz ...){if(_hiz<0 || _hiz>100) //gariplik var 1 yaphiz = 1;else //her şey yolundahiz = _hiz;}...}Sadece hıza odaklandık ve diğer satırları yazmadık. (Bu kodu kopyala yapıştır yapmayın, çalışmaz!)
İkinci yöntem bir yordam üzerinden bu özelliği kontrol etmektir. Bunun için set_hiz adımda private bir yordam olsun.
123456789101112131415161718 public class Futbolcu{private int hiz;...public Futbolcu(..., int _hiz ...){hiz = set_hiz(_hiz);}private void set_hiz(int _hiz) //bu _hız'la yukardaki _hız'ı karıştırmayın. Yerel değişken genel değişken kavramları.{if(_hiz<0 || _hiz>100)hiz = 1;else //her şey yolundahiz = _hiz;}...}void bir yordam değer döndürmez. set_hiz yordamı sadece yukarıdaki hız değişkenin içeriğine kontrollü bir şekilde ulaşılmasını sağlar.
Birinci sorunun cevabının sonunda set_hiz yordamını private yapmıştık. Eğer main bölümünden bu yordama ulaşmak istersek ne yapmalıyız.
Cevap:
Çok basit bir soru oldu. Cevap tabii ki Public yapmak olacak.
Hız değişkenini kontrollü biçimde değiştirebiliyoruz. Fakat, nesne oluşturulduktan sonra bu değişkenin içindeki değere sınıf dışından ulaşamıyoruz. Nasıl ulaşabiliriz.
Cevap:
Tabiki sınıf içindeki hiz değişkenini public yapıp değiştirebiliriz. Fakat bu durumda yazılan set_hiz yordamının bir işlevi kalmaz. Yine sınıf dışından 150 girilirse sınıf buna izin vermiş olur. Bu durumda bu değişkeni dışarıdan erişime açmak saçma olacaktır. bunun yerine hiz değişkeni türünden değer döndüren bir yordam yazarız. Bu yordamında ismi get_hiz olsun.
12345678910111213141516171819202122 public class Futbolcu{private int hiz;...public Futbolcu(..., int _hiz ...){hiz = set_hiz(_hiz);}public void set_hiz(int _hiz){if(_hiz<0 || _hiz>100)hiz = 1;else //her şey yolundahiz = _hiz;}public int get_hiz(){return hiz;}...}Hem set_hiz sayesinden kontrollü değiştirme şansına ulaştık, hem de get_hiz sayesinde hiz değişkenine girilen değeri kontrol altına aldık. Bu bölümü çok iyi anlamadan Property konusuna geçmeyin.
Property
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public class Futbolcu { private int hiz; ... public Futbolcu(..., int _hiz ...) { P_HIZ = _hiz; } public int P_HIZ { set { if(value<0 || value>100) hiz = 1; else //her şey yolunda hiz = value; } get { return hiz; } } ... } |
- Can a biologist fix a radio?—Or, what I learned while studying apoptosis, Volume 2, Issue 3, September 2002, Pages 179–182, Cancer Cell.