29
Mar'14

OOP 9: Abstract Kavramı ve Abstract Class (C# ile OOP)

Bu yazımda abstract(sanal) kavramına ve abstract sınıflara değinmeye çalışacağım.

 

Tabiki her şeyden önce böyle bir kavrama neden ihtiyaç duyduğumuzu araştırmak gerekir. Bunun için şimdiye kadar anlattıklarımdan fazlasını içermeyen bir yapı kuralım. Mesela elektronik eşya sınıfı ve bu sınıftan türemiş telefon ve bilgisayar adında iki adet sınıf olsun. İlk ihtiyacımız da bu eşyaların fiyatlarının hesaplanması olsun. Sınıfların içine bu fiyat hesaplama metodlarını da kodlayalım. Sonra ihtiyaçlarımızı biraz daha şekillendireceğiz. Anlatmaya çalıştığım yapının kodları aşağıdaki gibi olacaktır:

class ElektronikEsya
{
    public decimal Alisfiyati { get; set; }
    public decimal KarYuzdesi { get; set; }

    public decimal FiyatHesapla()
    {
        return Alisfiyati + (KarYuzdesi * Alisfiyati);
    }
}

class Telefon: ElektronikEsya { }

class Bilgisayar: ElektronikEsya { }

Main içerisini ise aşağıdaki şekilde kodlayarak telefon ve bilgisayar için fiyat hesaplaması yaptıralım.

static void Main(string[] args)
{
    Telefon telefon = new Telefon() 
    { 
        Alisfiyati = 1100, 
        KarYuzdesi = (decimal)20/100 
    };
    Console.WriteLine("Telefon fiyat: {0}", telefon.FiyatHesapla());

    Bilgisayar bilgisayar = new Bilgisayar() 
    { 
        Alisfiyati = 2000, 
        KarYuzdesi = (decimal)25/100 
    };
    Console.WriteLine("Bilgisayar fiyat: {0}", bilgisayar.FiyatHesapla());
}

Programı çalıştırdığımızda çıktı aşağıdaki gibi olacaktır.

oop9ilkFiyat
Fiyat hesaplama yapabilmek için base classtaki ortak bir metodu kullandık. Her ürün için aynı fiyat hesaplama yöntemi varsa bu iyi bir yol olabilir fakat ürünler için farklı farklı fiyat hesaplama yöntemlerine ihtiyaç duyabiliriz ve tüm ürünler için fiyat hesaplama metodu bir zorunluluk olabilir. Bu durumda base class’taki metodu virtual yapıp child class’ta override edebiliriz ama override etmeme lüksüne de sahibiz:) İstediğimiz, child class’ın bu metodu kullanmaya zorunlu olması. İhtiyacımızı karşılayan anahtar kelime abstract anahtar kelimesidir.

 

Biraz abstract anahtar kelimesinden bahsettikten sonra örneğe devam edebiliriz. Maddeler halinde sıralarsak:

 

– Abstract anahtar kelimesi hem metodlar için hem de classlar için kullanılabilir.

– Bir metodun abstract olarak işaretlenebilmesi için sınıfının da abstract olarak işaretlenmiş olması gerekmektedir.

– Abstract bir sınıf, hem abstract hem de abstract olmayan üyeler içerebilir.

– Abstract metodların gövdeleri ancak child sınıflarda kodlanabilir. Metodların gövdeleri abstract olarak işaretlendikleri abstract sınıflarda kodlanamazlar.

Şimdi ise biraz önce bahsettiğim gibi abstract anahtar kelimesini kodumuza ekleyelim. Sadece abstact anahtar kelimelerini eklediğimde sınıfın son hali aşağıdaki gibi olacaktır.

abstract class ElektronikEsya
{
    public decimal Alisfiyati { get; set; }
    public decimal KarYuzdesi { get; set; }

    public abstract decimal FiyatHesapla()
    {
        return Alisfiyati + (KarYuzdesi * Alisfiyati);
    }
}

Halen FiyatHesapla() metodunun gövedesi base class içerisinde kodlanmış ve ElektronikEsya classından türettiğimiz sınıflar FiyatHesapla() metoduna sahip değiller. Bu haliyle kodu derlemeye çalıştığımızda derleyici bizi aşağıdaki şekilde uyaracaktır.

oop9Errors1

1- Abstract olarak işaretlenen FiyatHesapla() metodunun gövdesi abstract olarak işaretlendiği sınıfta kodlanamaz.

2-3- Abstract olan ElektronikEsya sınıfından türetilen sınıflar, ElektronikEsya’nın abstract üyelerini içermek zorundadır.

 

Bir oop tasarımında, sınıf içerisinde abstract üyeler tanımlayarak, bu sınıftan türetilen sınıfları, tanımladığımız abstact üyelerin gövdelerini kodlamaya zorlayabiliriz. Örneğimiz üzerinden bir cümle kuracak olursak bir nevi şunu demiş oluruz: “Eğer sen bir elektronik eşya isen, fiyatını hesaplayabileceğim bir metodu bana sunmak zorundasın.”

 

Kaldığımız yerden devam edersek kodun son hali aşağıdaki gibi olacaktır. Bilgisayar fiyatı hesaplanırken ek bir masraf alındığını farz edelim.

abstract class ElektronikEsya
{
    public decimal Alisfiyati { get; set; }
    public decimal KarYuzdesi { get; set; }

    public abstract decimal FiyatHesapla();
}

class Telefon: ElektronikEsya 
{
    public override decimal FiyatHesapla()
    {
        return Alisfiyati + (KarYuzdesi * Alisfiyati);
    }
}

class Bilgisayar: ElektronikEsya 
{
    public decimal EkMasraf { get; set; }

    public override decimal FiyatHesapla()
    {
        return EkMasraf + Alisfiyati + (KarYuzdesi * Alisfiyati);
    }
}

Metodların gövdelerini kodlamak için override anahtar kelimesini kullandığımıza dikkat edelim. Burada override yerine new anahtar kelimesi kullanamazdık çünkü new anahtar kelimesi base class metodunun da kullanılmasına olanak tanıyordu önceki yazımdan hatırlarsanız. Burada ise base classta metodun gövdesi zaten yok.

 

Bilgisayar nesnesini belleğe çıkarırken(örneklerken) EkMasraf propertysine 100 vererek fiyatları tekrar hesaplatırsak main metodu ve çıktı aşağıdaki gibi olacaktır.

static void Main(string[] args)
{
    Telefon telefon = new Telefon() 
    { 
        Alisfiyati = 1100, 
        KarYuzdesi = (decimal)20/100 
    };
    Console.WriteLine("Telefon fiyat: {0}",telefon.FiyatHesapla());

    Bilgisayar bilgisayar = new Bilgisayar() 
    { 
        Alisfiyati = 2000, 
        KarYuzdesi = (decimal)25/100,
        EkMasraf = 100
    };
    Console.WriteLine("Bilgisayar fiyat: {0}", bilgisayar.FiyatHesapla());
}

oop9ikinciFiyat

Yukarıda kısa bir özet yapmıştım fakat değinmediğimiz birkaç noktaya da değinerek tekrar kısa bir özet geçme ihtiyacı duyuyorum.

 

Abstract bir sınıftan nesne örneklenemez.

– Abstract bir sınıf hem abstract hem de abstract olmayan üyeler barındırabilir.

– Abstract üyelerin gövdeleri child sınıflarda kodlanmak zorundadır.

– Abstract sınıflar içerisinde abstract üyelerin gövdeleri kodlanamaz. Sadece tanımları yapılır.

– Abstract sınıflar birçok açıdan interface‘lerle benzerlik gösterirler. Arasındaki benzerlik ve farklara sıradaki yazıda değiniyor olacağım.

– Yine bu konuyla yakından ilgili olan sealed anahtar kelimesine değinmeden olmaz.

Sealed Anahtar Kelimesi

– Sealed anahtar kelimesini sınıf adının yanına yazdığınızda artık o sınıftan başka sınıflar türetilemez.

– Eğer bir metod adının yanına yazılırsa o metod child sınıflarda override edilemez olacaktır.

Not: Sealed yapılmak istenen metod ana sınıfın metodu ise sealed anahtar kelimesini kullanamazsınız. Çünkü zaten bunu yapmak için o metodu virtual ya da abstract yapmamanız yeterlidir.

 

Bu iki durumu yukarıdaki örneklere benzer şekilde ilerleyerek kısaca gösterebiliriz.

sealed class ElektronikEsya
{
...

Yukarıdaki örneklerimiz için ana sınıf olan ElektronikEsya sınıfı, sealed anahtar kelimesi ile işaretlendiğinde aşağıdaki gibi bir hata alınacaktır.

Error ‘Abstract.Bilgisayar’: cannot derive from sealed type ‘Abstract.ElektronikEsya’

 

ElektronikEsya’dan türeyen Bilgisayar sınıfında override ettiğimiz FiyatHesapla() metodunu sealed olarak işaretlersek, Bilgisayar sınıfından türeyen sınıflar artık bu metodu override edemiyor olacaklardır. Kullanımı ise şu şekilde:

class Bilgisayar: ElektronikEsya 
{
    public override sealed decimal FiyatHesapla()
    {
...

Şimdilik bu kadar aklınızı karıştırmak yeter:) Örneklerle konuyu pekiştirmenizi tavsiye ederim. Unutmayın, yazılım okuyarak öğrenilmez. Yazılımı bize asıl öğreten yazdığımız kodlar ve neticesinden karşılaştığımız problemleri çözüme kavuşturmaktır.

 

İyi Eğlenceler:)

  • Cem Demir

    Eline sağlık Turgay, gayet açıklayıcı anlatmışsın.

Yeni makaleleri E-Mail ile takip edin!