Abstract class ile Interface, OOP geliştirmelerimizde en sık kullanılan 2 yapının ortak bazı özelliklerinden dolayı oldukça karıştırıldıkları bazı kısımlar yer almaktadır ve ciddi bazı farklarından ikisinin ayırt edici olduğu kısımlar bulunmaktadır, bu makalede iki yapının aralarındaki farklara madde madde gözatacağız.
Abstract class ile Interface Arasındaki Fark Nedir❓
Yeni yeni OOP prensiplerini benimseyerek yazılım geliştiren arkadaşların sıklıkla sorularını yönelttiği durumlardan biri olan ve mülakatlarda sorular sorular arasında da yer bulan bu durum için kodumun şu kısmında acaba abstract mı kullansam daha iyi olur yoksa interface mi kullanmalıyım gibi sorular yöneltiliyor, açıkçası bu soru ihtiyaç duyulan kısma göre kullanılabilmektedir. Şimdi hangi durumda abstract class ve hangi durumda interface kullanmalıyız bakalım.
Ama öncesinde hangi farkları olduğuna adım adım bakalım, sonrasında aynı örnek senaryo üzerinden söz dizimine bakalım.
💬 Farklar
- interface ve abstract class’lar new anahtar sözcüğü ile oluşturulamazlar.
- Bir sınıf birden fazla interface’i kalıtım olarak alabilir ama bir sınıfa bir tane abstract class kalıtım alınabilir.
- Interface içerisinde boş metodlar tanımlanabilir ama abstract class’larda hem boş metodlar tanımlanabilir hemde içi dolu metodlar tanımlabilir.
- Abstract sınıflar içerisinde metod gövdeleri tanımlanıp özellik değerleri ayarlandığı için genellikle sonradan üzerine ek geliştirilmek yapmak için kullanılıır ama interface de ise body ve değer set edilemediği için tamamen interface üzerinden tüm üyeleri implemente edilerek sıfırdan geliştirmeler yapılması gereken durumlarda kullanılır.
- Abstract class’lar içerisinde sadece abstract olarak işaretlenmiş metod ve özellikler implement edilmek zorundadır fakat interface içerisindeki tüm özellik ve metodlar implement edilmek zorundadır.
- Bir class bir tane abstract class’ı kalıtım olarak alabilir ama bir class istenilen sayıda interface’i kalıtım olarak alabilir.
- Interface içerisinde özellik ve metodlarda erişim belirleyiciler kullanılmaz herşey public olarak kabul edilir fakat abstract sınıflarda kullanılabilir.
- Abstract sınıflara diğer sınıf ve interface’ler kalıtım olarak geçilebilir fakat interface’e yine farklı interface’ler haricinde herhangi bir yapı kalıtım olarak geçilemez.
Örnek
O zaman örnek bir senaryo üzerinden yukarıdaki farkları daha da netleştirelim.
Bu örnekte aynı sayıda ve isimde üyeye sahip arayüz ve abstract class oluşturulacak EmployeeAbstract ve EmployeeInterface adında sınıflar oluşturulup arayüzden ve abstract classdan miras alacak şekilde geliştirme yapılacak. O zaman hemen ilgili interface ve abstract tanımlarını yapalım böylelikle hızlıca örneğimize geçiş yapalım.
IPerson.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | namespace MHG.AbstractInterfaceDifferent.Models { /// <summary> /// interface new anahtar sözcüğü ile oluşturulamaz. /// /// Bir sınıf birden fazla interface’i kalıtım olarak alınabilir. /// /// Interface içerisinde boş metodlar tanımlanabilir /// /// Interface içerisinde özellik ve metodlarda erişim belirleyiciler kullanılmaz fakat abstract sınıflarda kullanılabilir. /// </summary> interface IPerson { string Name { get; set; } string GetName(); string GetNameWithDesciption(); } } |
Person.cs
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 26 27 28 29 30 31 32 33 | namespace MHG.AbstractInterfaceDifferent.Models { /// <summary> /// Abstract sınıfa IPerson arayüzünü kalıtım olarak geçebildim ama tam tersi durum mümkün değil /// yani IPerson arayüzüne yine arayüz haricinde sınıfı kalıtım olarak geçemiyoruz. /// /// Interface içerisinde özellik ve metodlarda erişim belirleyiciler kullanılmaz fakat abstract sınıflarda kullanılabilir. /// </summary> public abstract class Person : IPerson // Buradaki arayüzü kalıtım olarak geçmemin bir esprisi yok dikkate almayınız sadece abstract class'a bir arayüzü kalıtım olarak geçebildiğimizi göstermek için ekledim :) { /// <summary> /// Bunu abstract olarak işaretlediğimiz için Person sınıfını kalıtım olarak /// alan sınıf bunu zorunlu olarak kendi içine implement edecektir. /// </summary> public abstract string Name { get; set; } /// <summary> /// Abstract class'larda hem boş metodlar tanımlanabilir hemde içi dolu metodlar tanımlabilir. /// </summary> /// <returns></returns> public string GetName() { return Name; } /// <summary> /// Abstract class'larda hem boş metodlar tanımlanabilir hemde içi dolu metodlar tanımlabilir. /// Abstract olarak işaretlendiğinden Person sınıfını kalıtım alan sınıf bu metodu implement etmek zorundadır. /// </summary> /// <returns></returns> public abstract string GetNameWithDesciption(); } } |
Not: Üstteki Person adlı abstract sınıfa IPerson adlı arayüzün geçilmesi ilgili satırdaki açıklamada yer aldığı gibi “arayüzü kalıtım olarak geçmemin bir esprisi yok dikkate almayınız sadece abstract class’a bir arayüzü kalıtım olarak geçebildiğimizi göstermek için ekledim :)” sadece arayüzlerin abstract sınıflara istenilirse miras olarak geçilebildiğini göstermek adına eklenmiştir.
abstract ve interface yapısı üzerinden aynı üyelere sahip nesnelerimiz oluşturduk ama abstract class’da dikkatinizi hemen bir konu çekmiştir GetName metodunun gövdesi yazılmış ama GetNameWithDescription() adlı metodun gövdesi yok ve abstract olarak işaretlenmiş o yüzden bu metodun gövdesinin tanım işi bu sınıfı miras alacak diğer sınıfa yüklenmiştir.
Sıradaki işlemimiz olan oluşturduğumuz arayüz ve abstract sınıftan türettiğimiz EmployeeAbstract ve EmployeeInterface tanımlarına gözatalım hızlıca.
EmployeeInterface.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | namespace MHG.AbstractInterfaceDifferent.Models { /// <summary> /// IPerson arayüzü içerisinde tanımlı olan 3 üyenin tümünü arayüz olduğundan implement etmek zorunda kaldım ve metod gövdelerini alttaki gibi doldurdum. /// </summary> class EmployeeInterface : IPerson { public string Name { get; set; } public string GetName() => Name; public string GetNameWithDesciption() => $"Bu Kullanıcının Adı: {Name}"; } } |
EmployeeAbstract.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | namespace MHG.AbstractInterfaceDifferent.Models { /// <summary> /// Abstract class içerisinde toplamda 2 metod ve bir özellik olarak 3 üye var ama sadece ikisini /// abstract olarak işaretlediğimizden Person EmployeeAbstract adlı sınıfımıza kalıtım olarak geçtiğimizden zorunlu olarak 2 üyeyi implement olarak geçtik. /// </summary> class EmployeeAbstract : Person { public override string Name { get; set; } public override string GetNameWithDesciption() => $"Bu Kullanıcının Adı: {Name}"; } } |
Elimden geldiğince kodlar arasına bazı önemli dipnotları tekrar yazdım lütfen bu dipnotları okumaya dikkat ediniz kodun ilgili kısımlarına dipnotları yazarak daha anlaşılır olmasını sağlamaya çalıştım umarım öyle de olmuştur.
O zaman hemen bu 2 farklı yapı üzerinden oluşturduğumuz Employee* nesneleri üzerinden aldığımız örnekler ve kullanımlarına ait örnek kod blokları altta yer almaktadır.
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 26 27 28 29 30 31 32 33 34 35 | using System; using MHG.AbstractInterfaceDifferent.Models; namespace MHG.AbstractInterfaceDifferent { class Program { static void Main(string[] args) { // Abstract class // new anahtar kelimesi ile oluşturamıyoruz -> Error CS0144 Cannot create an instance of the abstract class or interface 'Person' // var resAbstractError1 = new Person(); // Interface'ler için new anahtar kelimesinin zaten kullanılmadığını biliyorduk. Üstteki CS0144 nolu hata fırlatılacaktır. // var resInterfaceError1 = new IPerson(); // Person adlı abstract sınıfından türettiğimiz EmployeeAbstract adlı sınıfı artık new anahtar kelimesi ile nesne örneği alabiliyoruz. var resAbstract = new EmployeeAbstract {Name = "Murat ÖNER"}; var nameAbstract = resAbstract.GetName(); var nameWithDescriptionAbstract = resAbstract.GetNameWithDesciption(); Console.WriteLine($"Name Abstract: {nameAbstract}"); Console.WriteLine($"NameWithDescription Abstract: {nameWithDescriptionAbstract}"); // IPerson adlı arayüzden türettiğimiz EmployeeInterface adlı sınıfı artık new anahtar kelimesi ile nesne örneği alabiliyoruz. var resInterface = new EmployeeInterface { Name = "Sakine ÖNER" }; var nameInterface = resInterface.GetName(); var nameWithDescriptionInterface = resInterface.GetNameWithDesciption(); Console.WriteLine($"Name Interface: {nameInterface}"); Console.WriteLine($"NameWithDescription Interface: {nameWithDescriptionInterface}"); } } } |
Demo
Bu makalede abstract ve interface arasındaki farklar anlatılmaya çalışılmıştır seçilen örnek ve metod adları sadece ikisi arasındaki farkları gösterebilmek için seçilmiştir.
Makalede kullanılan örneğe ve C# ile ilgili diğer tüm örneklere github hesabımdan erişebilirsiniz. Buraya tıklayıp github hesabıma erişebilirsiniz.
📚 Abstract class ile Interface Benzeri Makaleler
✍ Lütfen olumlu-olumsuz tüm görüşlerinizi bana yorum yada mail yolu ile iletmeyi ihmal etmeyin.
🔗 Sosyal medya kanallarından makaleyi paylaşarak destek olursanız çok sevinirim.
👋 Bir sonraki makalede görüşmek dileğiyle.
Merhaba,
Main metodu içinde iki kez “EmployeeAbstract” sınıfını oluşturmuşsunuz. İlk satır “EmployeeAbstract” oluşturken ikinci satırdaki EmployeeInterface sınıfını oluşturması gerekmiyor mu? Benim kaçırdığım bir nokta mı var acaba?
// Person adlı abstract sınıfından türettiğimiz EmployeeAbstract adlı sınıfı artık new anahtar kelimesi ile nesne örneği alabiliyoruz.
var resAbstract = new EmployeeAbstract {Name = “Murat ÖNER”};
// IPerson adlı arayüzden türettiğimiz EmployeeInterface adlı sınıfı artık new anahtar kelimesi ile nesne örneği alabiliyoruz.
var resInterface = new EmployeeAbstract { Name = “Sakine ÖNER” };
Merhaba,
Evet, copy paste kurbanı olmuşum, teşekkürler dikkatin için.
Comment’de belirtmişim aslında ama kod hatalı olmuş. Düzelmeyi yaptım.