Serdar YILMAZ / Software Developer
Bizimkisi Bir “Bug” Hikayesi...
Akbank Bankacılık Merkezi
Serdar Yılmaz C# – Abstract Sınıflar

C# – Abstract Sınıflar

.netTamamen kalıtım amaçlı kullanacağımız temel sınıfları oluştururken Abstract anahtar sözcüğünü kullanırız. Abstract bir sınıf oluşturabilmek için erişim belirtecinden sonra “abstract” anahtar sözcüğünü yazmamız gerekmektedir. Abstract sınıflar içerisinde hem metot tanımlayabilir hem de arayüzler de olduğu gibi metot bildirimi yapabiliriz.

public abstract class TemelSinif
{
    public void Metot_1()
    {
        Console.WriteLine("Abstract sınıf içerisinde tanımlanmış metot.");
    }

    public abstract void Metot_2();
}

TemelSinif, abstract bir sınıf olduğu için sadece kalıtım amaçlı kullanılabilir. Metot_1(), TemelSinif‘dan türetilen sınıflara doğrudan aktarılacaktır. Bildirimi yapılmış olan Metot_2()‘nin ise türetilmiş sınıflar içerisinde tanımlanması (metot gövdesinin yazılması) gerekmektedir.

Abstract sınıflarda metot bildirimi yapabilmek için erişim belirtecinden sonra “abstract” anahtar sözcüğünü yazmamız gerekmektedir.

public class TuretilmisSinif : TemelSinif
{
    public override void Metot_2()
    {
        Console.WriteLine("Türetilmiş sınıf içerisinde tanımlanmış metot.");
    }
}

TuretilmisSınıf, TemelSinif‘dan türetildiği için TuretilmisSınıf içerisinde Metot_2()‘nin tanımlamasını yapmamız gerekmektedir. Bu örnekten de anlaşılacağı üzere abstract sınıfları arayüzler (interface) gibi kullanabiliriz.

Abstract sınıf içerisinde bildirimi yapılmış olan metotları (Bkz: Metot_2()) türetilmiş sınıflar içerisinde tanımlayabilmemiz için override anahtar sözcüğünü kullanmamız gerekmektedir.

class Program
{
    private static void Main(string[] args)
    {
        TuretilmisSinif turetilmisSinif = new TuretilmisSinif();
        turetilmisSinif.Metot_1();
        turetilmisSinif.Metot_2();
    }
}

Ekran çıktısı:
Abstract sınıf içerisinde tanımlanmış metot.
Türetilmiş sınıf içerisinde tanımlanmış metot.
Press any key to continue . . .

Abstract Sınıfların Normal Sınıflardan Farkı Nedir?

Fark 1: Normal sınıflar içerisinde metot bildirimi yapılamazken, Abstract sınıflar içerisinde tıpkı arayüzler de olduğu gibi metot bildirimi yapılabilir. Bildirimi yapılan metotlar, Abstract sınıftan türeyen sınıflar içerisinde tanımlanmak zorundadır.

Fark 2: Normal sınıflardan “new()” anahtar sözcüğü ile nesneler oluşturulabilir ancak Abstract sınıflar tamamen kalıtım amaçlı geliştirildiğinden Abstract sınıflardan nesne oluşturulamaz.

TuretilmisSinif turetilmisSinif = new TuretilmisSinif(); (Doğru)
TemelSinif temelSinif = new TemelSinif();                (Yanlış)

Abstract Sınıfların Arayüzlerden Farkı Nedir?

Fark 1: Arayüzlerde sadece metot bildirimi yapılabilirken Abstract sınıflarda hem metot bildirimi yapılabilir hem de metot tanımlanabilir.

Fark 2: Bir sınıfa sadece bir tane Abstract sınıf inherit edilebilir ancak aynı sınıfa birden fazla arayüz implement edilebilir.

public abstract class AbstractSinif_1
{
    public abstract void Metot_1();
}

public abstract class AbstractSinif_2
{
    public abstract void Metot_2();
}

public class TuretilmisSinif : AbstractSinif_1
{
    public override void Metot_1()
    {
        Console.WriteLine("Metot_1() tanımlandı.");
    }
}

TuretilmisSinif‘a Abstract sınıflardan sadece bir tanesini inherit edebiliriz. Yani TuretilmisSinif‘a hem AbstractSinif_1‘i hem de AbstractSinif_2‘yi inherit edemeyiz.
public class TuretilmisSinif : AbstractSinif_1 , AbstractSinif_2 {} // YANLIŞ!

Ancak bir Abstract sınıfa, başka bir Abstract sınıfı inherit ederek bu kısıtı kaldırmak mümkün.
public abstract class AbstractSinif_1 : AbstractSinif_2
{
    public abstract void Metot_1();
}

public abstract class AbstractSinif_2
{
    public abstract void Metot_2();
}

public class TuretilmisSinif : AbstractSinif_1 
{
    public override void Metot_1()
    {
        Console.WriteLine("Metot_1() tanımlandı.");
    }

    public override void Metot_2()
    {
        Console.WriteLine("Metot_2() tanımlandı.");
    }
}

AbstractSinif_1‘e AbstractSinif_2 inherit edildiği için, AbstractSinif_1‘den türetilen bir sınıf hem AbstractSinif_1 içerisinde bildirimi yapılmış olan metodu (Metot_1()) hem de AbstractSinif_2 içerisinde bildirimi yapılmış olan metodu (Metot_2()) içermek zorundadır.

Abstract Sınıflara Hangi Durumlar da İhtiyaç Duyarız

Yılın her bir ayı için bir sınıf oluşturmamız gerektiğini düşünelim ve bu sınıflar içerisinde ilgili ayın kaç günden oluştuğu, yılın kaçıncı ayı olduğu ve her bir gününün kaç saatten oluştuğu bilgilerini döndürecek metotların olmasını istediğimizi varsayalım.

public interface Ay
{
    int GunlerKacSaattir();
    int KacGundenOlusur();
    int YilinKacinciAyidir();
}

İlk başta aklımıza bir arayüz kullanmak gelebilir. Ay isminde bir arayüz tanımlayıp, içerisinde ihtiyacımız olan metotların bildirimini yaptıktan sonra bu arayüzü aylarımızı temsil eden sınıflara implement ederek bir çözüm geliştirebiliriz.
public class Ocak : Ay
{
    public int GunlerKacSaattir()
    {
        return 24;
    }
   
    public int KacGundenOlusur()
    {
        return 31;
    }

    public int YilinKacinciAyidir()
    {
        return 1;
    }
}

public class Subat : Ay
{
    public int GunlerKacSaattir()
    {
        return 24;
    }

    public int KacGundenOlusur()
    {
        return 28;
    }

    public int YilinKacinciAyidir()
    {
        return 2;
    }
}

public class Aralik : Ay
{
    public int GunlerKacSaattir()
    {
        return 24;
    }

    public int KacGundenOlusur()
    {
        return 31;
    }

    public int YilinKacinciAyidir()
    {
        return 12;
    }
}

Ancak ayları temsil eden sınıfları dikkatlice inceleyecek olursak, GunlerKacSaattir() metodunun hepsinde aynı sonucu döndürecek şekilde tanımlandığını görebiliriz. Her bir ay için aynı metodu tekrar tekrar tanımlayıp kod tekrarı yapmak yerine, bir defaya mahsus tanımlamak çok daha verimli olacaktır. Arayüzler içerisinde metot tanımı yapılamayacağından, bu örnekte arayüz yerine abstract sınıf kullanacağız.
public abstract class Ay
{
    public int GunlerKacSaattir()
    {
        return 24;
    }

    public virtual int KacGundenOlusur()
    {
        return 31;
    }

    public abstract int YilinKacinciAyidir();
}

İçerisinde hem metot tanımı hem de metot bildirimi yapabileceğimiz bir yapıya ihtiyacımız olduğundan Ay isminden bir abstract sınıf oluşturduk. GunlerKacSaattir() metodu tüm aylar için aynı sonucu döndüreceğinden, bu metodu direkt abstract sınıf içerisinde tanımladık. Böylece 12 ay için aynı metodu 12 defa yazmak yerine, bir defa yazmış olduk.

Eğer bir metot tüm türetilmiş sınıflarda aynı şekilde tanımlanıyorsa o metodu abstract sınıf içerisinde standart bir metot tanımlar gibi tanımlarız.

KacGundenOlusur() metodunu abstract sınıf içerisinde tanımlamak yerine sadece bildirimini yapıp, Ayları temsil eden sınıflarımız içerinde tanımlayabilirdik. Ancak bu metot Ocak, Mart, Mayıs, Temmuz, Ağustos, Ekim ve Aralık ayları için aynı sonucu (31) döndürmesi gerektiğinden, en azından bu aylar için tekrardan KacGundenOlusur() metodunun tanımını yapmamak adına varsayılan olarak geriye 31 döndüren ancak istenilen sınıf içerisinde override edilerek yeniden tanımlanabilecek şekilde kullanılabilmesi için virtual olarak tanımladık (Bkz: C# – Virtual Metotlar).

Eğer bir metot bir çok türetilmiş sınıfta aynı şekilde tanımlanıyor iken sadece bir kaçında değişik şekilde tanımlanıyorsa o metot abstract sınıf içerisinde virtual olarak tanımlanır.

YilinKacinciAyidir() metodu her bir ay için farklı bir değer döndüreceğinden, bu metodun sadece bildirimi yapıyoruz.

Eğer bir metot tüm türetilmiş sınıflarda farklı şekilde tanımlanıyorsa o metodun abstract sınıf içerisinde sadece bildirimi yapılır.

public class Ocak : Ay
{            
    public override int YilinKacinciAyidir()
    {
        return 1;
    }
}

public class Subat : Ay
{
    public override int KacGundenOlusur()
    {
        return 28;
    }

    public override int YilinKacinciAyidir()
    {
        return 2;
    }
}

public class Aralik : Ay
{
    public override int YilinKacinciAyidir()
    {
        return 12;
    }
}

Serdar YILMAZ


Bu İçeriği Arkadaşlarınızla Paylaşmak İster misiniz?

4 Yorum

  1. chatay
    19 Ağustos 2020 de 22:19 · Cevapla

    çok güzel bir makale, ellerine sağlık.

  2. selami
    30 Mayıs 2020 de 00:58 · Cevapla

    çok temiz anlaşılır güzel bir makale olmuş teşekkürler

  3. Bora
    3 Aralık 2019 de 12:36 · Cevapla

    Çok güzel ve ayrıntılı bir anlatım olmuş emeğiniz için teşekkür ederim

  4. Mehmet
    30 Temmuz 2019 de 13:22 · Cevapla

    Teşekkürler abstract ve override kavramlarını çok iyi anladım sayenizde.

Bir Yorum Yapın