Makale Özeti

Kalıtım konusunu, çok biçimliliği de ele alarak incelemeye devam ediyoruz

Makale

Merhaba,

Bir önceki yazıda kalıtımdan bahsetmiştik, bu yazımızda da bu konuyu biraz daha derinlemesine inceleyeceğiz ve polymorphism, yani çok biçimlilik konusuna da giriş yapacağız.

Sınıflar ve kalıtım her ne kadar bize kodun yeniden kullanımı açısından güzel olanaklar sağlasa da nesneye yönelik programlama bize bundan çok daha fazlasını sunuyor. Bir önceki yazıda uyguladığımız ve aslında yanlış olan tekniğin yerine bu defa memur sınıfını polymorphism kullanarak yeniden tasarlayalım:

 

      public class Memur

      {

            private int yas;

            private string isim;

           

            public Memur()

            {

                  yas=30;

                  isim="Memur bey";

            }

            public int getyas()

            {

                  return yas;

            }

            public void setyas(int yeniyas)

            {

                  yas=yeniyas;

            }

            public string getisim()

            {

                  return isim;

            }

            public void setisim(string yeniisim)

            {

                  isim=yeniisim;

            }

            public virtual void raporyaz()

            {

                  Console.WriteLine("Memurun raporu: Her şey yolunda");

            }

            public void  telefonet(string telno)

            {

                  Console.WriteLine(telno + " numaralı telefonu aradım");

            }

      }

 

Aslında buradaki tek değişiklik, raporyaz fonksiyonunu virtual bir fonksiyon olarak tanımlamamız. Bu sayede memurdan türeyen sınıfların, bu fonksiyonun kendilerine ait bir versiyonunu sağlayabileceğini bildiriyoruz. (DİKKAT: sağlayabilmek dediğimize göre, isteyen sınıflar hala bu fonksiyonun memur sınıfı içindeki halini de kalıtımla olduğu gibi kullanabilir. ) Yani demek istediğiz şey şu: bu fonksiyon, daha sonra içerisinde bulunduğu sınıftan türeyecek sınıflar tarafından değişik şekilde yeniden yapılandırılabilir.

 

Bu durumda tapumemuru sınıfı da , override anahtar kelimesi ile raporyaz fonksiyonunun kendine ait bir versiyonunu sağladığını bildiriyor: (yani diyorki: ben türediğim sınıfdaki raporyaz fonksiyonunu daha farklı bir şekilde hayata geçireceğim, implement edeceğim)

 

public class TapuMemuru:Memur

      {

            public TapuMemuru()

            {

            }

            public override void raporyaz()

            {

                  Console.WriteLine("Tapu memurunun raporu: Ormanları kimseye vermiyoruz!!!");

            }

            public void istimlaket(string parcelno)

            {

                  Console.WriteLine(parcelno + " nolu arsa istimlak edilmiştir.");

            }

      }

 

Hmm, biraz karışmaya başladı galiba ? Neden bu anahtar kelimeler ile cümle aleme bu sınıfların aile ilişkilerini ilan ettik ki ?

İsterseniz bu soruya yanıt verebilmek için bir de sskmemuru yaratalım:

 

public class SSKMemuru:Memur

      {

            public SSKMemuru()

            {

            }

            public override void raporyaz()

            {

                  Console.WriteLine("SSK memurunun raporu: ilaç paraları ödendi!!!");

            }

           

            public void fakscek()

            {

                  Console.WriteLine("SSK genel müdürlüğüne faks çekildi");

            }

      }

 

Bu memur, kendi sınıfına ait yeni bir özellik olarak faks çekebiliyor, ve kendi sınıfına ait bir şekilde rapor yazıyor. Burada da türediği sınıf olan memurun rapor yazma özelliğini override ediyor. 

Şimdi isterseniz şöyle bir durum düşünelim, diyelim ki elimizde bir de amir sınıfı var. Bu sınıfın işi de beraber çalıştığı memurları yönetmek, onlardan rapor istemek. Yani memur sınıfından türemiş diğer sınıfların raporyaz fonksiyonunu kullanacağız. Hemen kabaca bir amir sınıfı tanımlayıp onun üzerinden gidelim:

 

public class Amir:Memur

      {

 

            public Amir()

            {

            }

           

      }

Burada da amir sınıfının da memur’dan türediğini görebiliyoruz. Eh, amirler de sonuçta memur olduğu için bu pek mantıksız bir tanım değil. Ancak bizim örneğimizde kullandığımız bu amir sınıfı memurdan türemede de olurdu.  Şimdi amirin diğer memurlardan rapor isteme davranışını tanımlayacağız: bunu yapan fonksiyonu siz olsanız nasıl yazardınız ???

( Lütfen bu noktada bu yazıyı okumayı durdurup bir süre düşünün, bir fikriniz olunca devam edin ....)

 

Evet muhtemelen ilk aklınıza gelebilecek olan çözümlerden birisini hayata geçirelim: raporiste diye bir fonksiyon yaratıp bu fonksiyona yolladığımız memurlardan rapor isteyelim.

 

Ancak memurlarımız değişik sınıflardan geliyor, bu durumda farklı sınıflar için bu fonksiyonun overload edilmiş  versiyonlarını oluşturmak en doğal çözüm olacaktır:

 

public class Amir:Memur

      {

 

            public Amir()

            {

            }

            public void memurdanraporiste(SSKMemuru muzaffer)

            {

                  muzaffer.raporyaz();

            }

            public void memurdanraporiste(TapuMemuru muzaffer)

            {

                  muzaffer.raporyaz();

            }

      }

Bu halde amir sınıfı istediğimizi yapacak gibi.

 

                  TapuMemuru muzaffer=new TapuMemuru();

                 

                  SSKMemuru muzaffer_ssk=new SSKMemuru();

                 

                  Amir SinirliAmir=new Amir();

 

                  SinirliAmir.memurdanraporiste(muzaffer);

 

                  SinirliAmir.memurdanraporiste(muzaffer_ssk);

 

Bu şekilde bir kullanım ile amirimiz her memurundan rapor alabiliyor. Ve kodumuz derlenip çalışınca

Tapu memurunun raporu: Ormanları kimseye vermiyoruz!!!

SSK memurunun raporu: ilaç paraları ödendi!!!

Press any key to continue

 

Şeklinde bir çıktı alıyoruz.

 

(bu örneği polymuzaffer.cs dosyasında bulabilirsiniz. )

 

Hmm, peki bu işi bir aşama ileri götüremezmiyiz ? Sonuçta ssk memuru ve tapu memuru aynı sınıftan türediler, yani SSK memuru bir memurdur, ve tapu memuru bir memurdur ifadeleri doğru ifadelerdir. Yani memur cinsinden bir parametre alan bir fonksiyon bunların ikisini de kabul edebilir mi ? tabii ki eder. Ancak polimorphism’in asıl gücü bizim karşımıza daha değişik şekilde çıkıyor:

Memur sınıfına yaratılan bir referansa memurdan türeyen bir sınıfı atarsanız, ve bu sınıfın override ettiği bir fonksiyonu çağırırsanız, her sınıf kendi metodunu çağırır!!

Karışık olduğunun farkındayım, hemen yeni fonksiyonun içine bakalım:

 

public void raporiste(Memur muzaffer)

            {

                  muzaffer.raporyaz();

            }

 

Bakın bu  fonksiyon diyor ki, bana bir memur yolla, ve o memur da rapor yazsın. Burada istemci olan amir sınıfı hangi memurun ne sınıftan olduğu ile ilgilenmek veya daha ötesi bilmek zorunda bile değil. Sonuçta amir hangi memuru çevirip rapor istese, her memur kendisi nasıl rapor yazacağını bilecektir. Amirin detaylar ile ilgilenmesine  ne gerek var  ki ?

 

Kodumuzun son hali:

 

TapuMemuru muzaffer=new TapuMemuru();

                 

                  SSKMemuru muzaffer_ssk=new SSKMemuru();

                 

                  Amir SinirliAmir=new Amir();

 

                  SinirliAmir.memurdanraporiste(muzaffer);

 

                  SinirliAmir.memurdanraporiste(muzaffer_ssk);

 

                  SinirliAmir.raporiste(muzaffer);

                  SinirliAmir.raporiste(muzaffer_ssk);

 

 

Şeklinde olacaktır. En sonra aynı fonksiyona iki ayrı sınfın üyelerini gönderip, direk olarak raporyaz fonksiyonlarını çağırıyoruz, ve her sınıf kendisi otomatik olarak kendi versiyonunu çalıştırıyor !! bu sayede çağıran fonksiyon binlerce değişik memurdan türemiş sınıfı çağırabilir. Çok biçimlilik sayesinde her sınıf kendi metodunu çalıştıracaktır. Buradaki örnekleri gerçek bir senaryoya dönüştürmek istiyorsanız, hemen size bir örnek vereyim:

 

Diyelim ki SQL server, oracle, access dosyası gibi değişik kaynaklara erişen sınıflarınız var. Ve hepsi de DatabaseAccess diye bir temel sınıftan türüyor ve bu temel sınıftan gelen baglantiac() fonksiyonunu override ediyor.

 

Başka bir sınıfda veriyi alıp işleyen bir fonksiyonunuz olsa, tek yapacağınız, istediğiniz sınıfı parametre olarak geçip, baglantiac() ‘ı çağırmak . Her sınıf kendi implementasyonuna göre değişik bir veritabanına bağlantı açacaktır. Gereksiz yere if kullanarak gelen sınıfın türünü almanıza gerek yok!!

 

public void baglantikullan(DatabaseAccess hedefsinif)

            {

                  hedefsinif.baglantiac();

                  //baglantıyı kullan

                  //.....

            }

Bu şekilde bir fonksiyon ile çok temiz bir şekilde çalışabilirsiniz. Her sınıf farklı şekilde davranarak çok biçimlilik sergileyecektir.

 

Nesneye yönelik programlamada işimizi oldukça kolaylaştıran bir özellik olan polymorphism ve bize getirdikleri üzerine bir sonraki yazıda kafa yormaya devam edeceğiz.O zamana kadar, bu yazıdaki fikirleri iyice kafanızda oturtmaya çalışın :)


Şeref Arıkan
Not: yazıdaki kodlar için lütfen tıklayın