C# Abstract (Soyut) Sınıflar ve Kullanımları
C# meraklısı ve kendini geliştirmek isteyen yazılım uzmanlarına yeniden merhabalar :)
Bu makalemizde inheritance (kalıtım) makale dizimizi sürdürüyoruz ve bugün abstract sınıfları öğreniyoruz.
Abstact sözcüğünü soyut ya da özet olarak Türkçe'ye çevirebiliriz ancak teknik olarak devam edersek kendisinden kalıtım veren ancak new anahtar sözcüğüyle instance (örnek kopya) alınamayan sınıflardır diyebiliriz.
Aynı zamanda bir abstract sınıf içerisinde yine abstract sözcüğünü kullanarak metotlar oluşturabilir ve böylece abstract sınıfı tıpkı bir interface (arayüz) gibi kullanabiliriz,bu özelliği ile bazı yazılımcılar interface yerine abstract class kullanmayı tercih ederler.Makalenin sonuna doğru abstract classı interface gibi kullanırken uymamız gereken kurallara değineceğiz.
Abstact classlar bir sonraki C# makalemizde öğreneceğimiz sealed (mühürlü) anahtar sözcüğüyle kullanılamazlar çünkü abstract sadece kalıtım veren anlamına gelirken sealed kalıtım vermeyen anlamına gelmektedir.Demek ki abstract bir sınıfı sealed ile işaretlemeye çalışırsak "ne kalıtım verir ne vermez" gibi saçma bir mantık doğar :)
Bu kadar özetten sonra sıra geldi kod yazmaya..
Şimdi Visual Studio'yu açıyor ve C# programlama dilinde yeni bir Windows Form projesi oluşturuyoruz.Ardından
"kedi" adında bir abstract class oluşturuyoruz:
Abstact classımız tıpkı normal bir class niteliğinde olduğu için içerisine property ve metotlarımızı yazıyoruz:
Soyut sınıfımızı oluşturduktan sonra formumuzun load eventi (olayı) içerisinde new anahtar sözcüğüyle instance almaya
çalışıyor ve ortaya çıkan hatayı görüyoruz:
Visual Studio'nun bahsettiği gibi abstract olarak işaretli bir sınıftan instance alınamaz demiştik,ancak abstract class
başka bir sınıfa kalıtım verebilir.O yüzden "mıncır" adında bir kedimiz olsun ve abstract olarak yazdığımız kedi sınıfından
kalıtım alsın:
Formumuza tekrar dönüyoruz ve mıncır sınıfından instance alıyoruz:
Böylece abstract sınıftan kalıtım alan normal bir sınıftan instance alınabildiğini öğrenmiş oluyoruz :)
Buraya kadar öğrendiğimiz konu oldukça kolaydı diyebiliriz şimdi gelelim makalemizin başında da bahsettiğimiz gibi
abstract bir sınıfı interface gibi kullanmaya...
Abstact bir sınıfı interface gibi kullanmak için uyacağımız en önemli kural, sınıf içerisindeki hangi üyeyi interface
olarak kullanmak istiyorsak o üyenin başına mutlaka abstract sözcüğünü eklemek ve erişim tipini private olarak belirtmemek zorundayız.
Eğer bir abstract classı interface gibi kullanmaya karar verirseniz, sınıf içerisindeki metotların başına abstract sözcüğünü kullanacağınız için metotlarınız mutlaka ama mutlaka erişim belirteçlerinden (access modifiers - ileride göreceğiz) public (her yere açık şekilde) olarak tanımlanmak zorundadırlar.
Bunun yanı sıra abstract metotları virtual (sanal) olarak işaretleyemeyiz çünkü abstract sınıf kalıtım verme niteliğinde olduğu için zaten sanal yapıdadırlar.
Interface gibi kullanmak istediğimiz metotlar static (durağan) olarak belirtilemezler çünkü interface mantığında static kavramına yer yok. (Kalıtım veren dinamik yapıdadır her zaman)
Şimdi tekrar Visual Studio'ya geri dönüyor ve "köpek" adında yeni bir abstract class oluşturuyoruz.Bu sınıfımız
içerisindeki metotlara dikkat ederseniz tamamının başında abstract olduğunu ve interface konusunda öğrendiğimiz
gibi metodun içinin boş yalnızca gövdesinin olduğunu göreceksiniz:
Kopek sınıfımızdan çomar isimli köpeğimiz için "comar" adında bir sınıf oluşturuyor ve kopek sınıfından kalıtım alıyoruz:
Sanki normal bir interface'den kalıtım almış gibi sınıfımız üyeleri otomatik biçimde doluyor ve metotlarımızın içerisini
doldurmamız için metot içerikleri genişletiliyor.
Bir abstract class ile interface'den kalıtım almanın en önemli farkı şudur: kalıtım alacak sınıf birden çok interface'den
kalıtım alabiliyorken, interface gibi davranan abstract sınıflardan en çok bir kalıtım alabilmektedir.
Yani çoklu kalıtım almak istiyorsak her zaman interface'leri tercih etmeliyiz. (Dolaylı kalıtım hariç - birazdan öğreneceğiz)
Abstact sınıfların bir başka özelliği ise bir abstract sınıf hem interface gibi hem de kalıtım vermeyen normal bir sınıf
gibi davranabilir, kafanız karışmasın hem interface'dir hem de değildir :)
Peki nasıl oluyor?
Abstact bir sınıf içerisindeki metotlardan hangisinin başında abstract yazıyorsa o metot interface üyesi olarak varsayılırken başında abstract yazmayan metotlar normal bir sınıf üyesi gibi davranırlar ve doğal olarak interface gibi davranmasını istediğimiz metotlar yalnızca gövde yapısındayken normal metot yapısında çalışan metotların içine istediğimiz kodları yazabiliriz.
Gelelim pratik bir örneğe...
"Tavsan" adında bir abstract sınıf oluşturalım ve içerisine abstract olan "koş", abstract olmayan "zıpla" isimli iki metot ve tipi (string,int) önemli olmayan abstract olan ve olmayan renk ve yaş property'leri ekleyelim:
Şimdi de "Fındık" adında bir sınıf oluşturalım ve abstract olan tavşan sınıfımızdan kalıtım alalım:
Dikkat ederseniz kalıtım aldıktan sonra yalnızca interface gibi davranan "koş" metodumuzun gövdesi "fındık" isimli sınıfımızın içerisinde dolduruldu.Interace gibi davranmayan "zıpla" isimli metodumuz ise aslında bir yere kaybolmadı,arka planda bizi bekliyor.
"Fındık" isimli metodumuzdan instance alıyoruz:
Gördüğünüz gibi soyut sınıfında oluşturduğumuz metotların ikiside geldi ancak aralarındaki tek fark; interface gibi davranan metodun ne yapacağı "normal" isimli metotta belirlenirken diğeri soyut isimli sınıfımızda baştan belirlendi.
Kişisel tercihim olarak bir abstract sınıfı ya abstract olarak kullanırım ya da hiç kullanmayıp interface'lerden yararlanırım,tabi sizin farklı bir proje stratejiniz varsa bir abstract sınıfı hem normal bir sınıf gibi kullanabilir hem de interface gibi tasarlayabilirsiniz.
Abstact sınıfları da öğrendiğimize göre bir sonraki makalemizde görüşmek üzere hoşçakalın :)
Bu makalemizde inheritance (kalıtım) makale dizimizi sürdürüyoruz ve bugün abstract sınıfları öğreniyoruz.
Abstact sözcüğünü soyut ya da özet olarak Türkçe'ye çevirebiliriz ancak teknik olarak devam edersek kendisinden kalıtım veren ancak new anahtar sözcüğüyle instance (örnek kopya) alınamayan sınıflardır diyebiliriz.
Aynı zamanda bir abstract sınıf içerisinde yine abstract sözcüğünü kullanarak metotlar oluşturabilir ve böylece abstract sınıfı tıpkı bir interface (arayüz) gibi kullanabiliriz,bu özelliği ile bazı yazılımcılar interface yerine abstract class kullanmayı tercih ederler.Makalenin sonuna doğru abstract classı interface gibi kullanırken uymamız gereken kurallara değineceğiz.
Abstact classlar bir sonraki C# makalemizde öğreneceğimiz sealed (mühürlü) anahtar sözcüğüyle kullanılamazlar çünkü abstract sadece kalıtım veren anlamına gelirken sealed kalıtım vermeyen anlamına gelmektedir.Demek ki abstract bir sınıfı sealed ile işaretlemeye çalışırsak "ne kalıtım verir ne vermez" gibi saçma bir mantık doğar :)
Bu kadar özetten sonra sıra geldi kod yazmaya..
Şimdi Visual Studio'yu açıyor ve C# programlama dilinde yeni bir Windows Form projesi oluşturuyoruz.Ardından
"kedi" adında bir abstract class oluşturuyoruz:
Abstact classımız tıpkı normal bir class niteliğinde olduğu için içerisine property ve metotlarımızı yazıyoruz:
Soyut sınıfımızı oluşturduktan sonra formumuzun load eventi (olayı) içerisinde new anahtar sözcüğüyle instance almaya
çalışıyor ve ortaya çıkan hatayı görüyoruz:
Visual Studio'nun bahsettiği gibi abstract olarak işaretli bir sınıftan instance alınamaz demiştik,ancak abstract class
başka bir sınıfa kalıtım verebilir.O yüzden "mıncır" adında bir kedimiz olsun ve abstract olarak yazdığımız kedi sınıfından
kalıtım alsın:
Formumuza tekrar dönüyoruz ve mıncır sınıfından instance alıyoruz:
Böylece abstract sınıftan kalıtım alan normal bir sınıftan instance alınabildiğini öğrenmiş oluyoruz :)
Buraya kadar öğrendiğimiz konu oldukça kolaydı diyebiliriz şimdi gelelim makalemizin başında da bahsettiğimiz gibi
abstract bir sınıfı interface gibi kullanmaya...
Abstact bir sınıfı interface gibi kullanmak için uyacağımız en önemli kural, sınıf içerisindeki hangi üyeyi interface
olarak kullanmak istiyorsak o üyenin başına mutlaka abstract sözcüğünü eklemek ve erişim tipini private olarak belirtmemek zorundayız.
Eğer bir abstract classı interface gibi kullanmaya karar verirseniz, sınıf içerisindeki metotların başına abstract sözcüğünü kullanacağınız için metotlarınız mutlaka ama mutlaka erişim belirteçlerinden (access modifiers - ileride göreceğiz) public (her yere açık şekilde) olarak tanımlanmak zorundadırlar.
Bunun yanı sıra abstract metotları virtual (sanal) olarak işaretleyemeyiz çünkü abstract sınıf kalıtım verme niteliğinde olduğu için zaten sanal yapıdadırlar.
Interface gibi kullanmak istediğimiz metotlar static (durağan) olarak belirtilemezler çünkü interface mantığında static kavramına yer yok. (Kalıtım veren dinamik yapıdadır her zaman)
Şimdi tekrar Visual Studio'ya geri dönüyor ve "köpek" adında yeni bir abstract class oluşturuyoruz.Bu sınıfımız
içerisindeki metotlara dikkat ederseniz tamamının başında abstract olduğunu ve interface konusunda öğrendiğimiz
gibi metodun içinin boş yalnızca gövdesinin olduğunu göreceksiniz:
Kopek sınıfımızdan çomar isimli köpeğimiz için "comar" adında bir sınıf oluşturuyor ve kopek sınıfından kalıtım alıyoruz:
Sanki normal bir interface'den kalıtım almış gibi sınıfımız üyeleri otomatik biçimde doluyor ve metotlarımızın içerisini
doldurmamız için metot içerikleri genişletiliyor.
Bir abstract class ile interface'den kalıtım almanın en önemli farkı şudur: kalıtım alacak sınıf birden çok interface'den
kalıtım alabiliyorken, interface gibi davranan abstract sınıflardan en çok bir kalıtım alabilmektedir.
Yani çoklu kalıtım almak istiyorsak her zaman interface'leri tercih etmeliyiz. (Dolaylı kalıtım hariç - birazdan öğreneceğiz)
Abstact sınıfların bir başka özelliği ise bir abstract sınıf hem interface gibi hem de kalıtım vermeyen normal bir sınıf
gibi davranabilir, kafanız karışmasın hem interface'dir hem de değildir :)
Peki nasıl oluyor?
Abstact bir sınıf içerisindeki metotlardan hangisinin başında abstract yazıyorsa o metot interface üyesi olarak varsayılırken başında abstract yazmayan metotlar normal bir sınıf üyesi gibi davranırlar ve doğal olarak interface gibi davranmasını istediğimiz metotlar yalnızca gövde yapısındayken normal metot yapısında çalışan metotların içine istediğimiz kodları yazabiliriz.
Gelelim pratik bir örneğe...
"Tavsan" adında bir abstract sınıf oluşturalım ve içerisine abstract olan "koş", abstract olmayan "zıpla" isimli iki metot ve tipi (string,int) önemli olmayan abstract olan ve olmayan renk ve yaş property'leri ekleyelim:
Şimdi de "Fındık" adında bir sınıf oluşturalım ve abstract olan tavşan sınıfımızdan kalıtım alalım:
Dikkat ederseniz kalıtım aldıktan sonra yalnızca interface gibi davranan "koş" metodumuzun gövdesi "fındık" isimli sınıfımızın içerisinde dolduruldu.Interace gibi davranmayan "zıpla" isimli metodumuz ise aslında bir yere kaybolmadı,arka planda bizi bekliyor.
"Fındık" isimli metodumuzdan instance alıyoruz:
Gördüğünüz gibi soyut sınıfında oluşturduğumuz metotların ikiside geldi ancak aralarındaki tek fark; interface gibi davranan metodun ne yapacağı "normal" isimli metotta belirlenirken diğeri soyut isimli sınıfımızda baştan belirlendi.
Kişisel tercihim olarak bir abstract sınıfı ya abstract olarak kullanırım ya da hiç kullanmayıp interface'lerden yararlanırım,tabi sizin farklı bir proje stratejiniz varsa bir abstract sınıfı hem normal bir sınıf gibi kullanabilir hem de interface gibi tasarlayabilirsiniz.
Abstact sınıfları da öğrendiğimize göre bir sonraki makalemizde görüşmek üzere hoşçakalın :)