Çoklu Kalıtım (Multiple Inheritance) ve Elmas Sorunu (Diamond Problem)Beğen
Çoklu Kalıtım, tanım olarak bir sınıfın aynı anda birbirinden bağımsız birden çok sınıftan türeyebilmesini ifade eder. Örneğin, "Nepenthes" sınıfını "Plant" sınıfından türetebileceğimiz gibi "Carnivorous" sınıfından da türetebiliriz. Her bitki etçil olmadığı için bu iki sınıf birbirinden bağımsızdır. İşte bu tarz bir durumda ortaya çıkan çoklu kalıtım özelliğini C++ dili desteklerken, daha modern Java ve C# dilleri desteklememektedir.
Esasında Nesne Yönelimli Programlama prensiplerine çok da yakışmayan Çoklu Kalıtım özelliği, modern nesne yönelimli dillerde Elmas Problemi denen bir probleme takılmaktadır. Nedir bu elmas problemi? Örnekleyelim:
public class Organism
{
public virtual void Feed()
{
Debug.WriteLine("Feeding...");
}
}
public class Plant : Organism
{
public override void Feed()
{
Debug.WriteLine("Doing photosynthesis...");
}
}
public class Carnivorous : Organism
{
public override void Feed()
{
Debug.WriteLine("Eating another organism...");
}
}
public class Nepenthes : Carnivorous, Plant
{
}
public class SampleRunner
{
public static void Run()
{
var nepenthes = new Nepenthes();
nepenthes.Feed();
}
}
C# ile yukarıdaki gibi sınıflar tanımladığımızda, compiler zaten "Class 'Nepenthes' cannot have multiple base classes: 'Carnivorous' and 'Plant'" hatası verecek ve kodlarımız derlenmeyecektir. Bu hatanın olmadığını varsayıp derlendiğini düşünelim. Bu durumda; Run betiğinde yer alan nepenthes varlığının "Feed" metodu çağırıldığında uygulama alt sınıflardan hangisine ait Feed metodunu çağıracaktır? Görüldüğü üzere Plant ve Organism sınıflarında Feed metodu override edilmiş ve elimizde iki farklı implementasyon var. Uygulamanın hangisini neye göre seçeceği problemi tam olarak elmas problemini anlatmaktadır. (Aşağıdaki gibi elmas şekline benzer bir kalıtım diyagramı probleme adını vermektedir.)
Bu problem .Net platformunda sınıflar yerine arayüzler kullanılarak çözülmektedir. Şöyle ki:
public interface IOrganism
{
void Feed();
}
public interface ICarnivorous : IOrganism
{
}
public interface IPlant : IOrganism
{
}
public class Nepenthes : IPlant, ICarnivorous
{
public override void Feed()
{
Debug.WriteLine("Eating another organism...");
}
}
Yukarıdaki gibi etçiller ve bitkiler için birer arayüz tanımlayarak, arayüzlerin gerektirdiği implementasyonu Nepenthes sınıfında sağlayabiliriz. Bu şekilde Nepenthes sınıfı etçil ve bitki görüntülerine sahip olacaktır. (Ben arayüzleri görüntülere ya da silüetlere benzetiyorum) Bu sayede;
public static void Run()
{
var nepenthes = new Nepenthes();
nepenthes.Feed();
var plant = (IPlant) nepenthes;
plant.Feed();
var carnivorous = (ICarnivorous)nepenthes;
carnivorous.Feed();
}
nepenthes nesnesini yukarıdaki gibi farklı görüntülerde kullanabiliriz.