Çok Biçimlilik (Polymorphism) Nedir, Ne İşe Yarar?Beğen
Çok biçimlilik bir nesnenin, kalıtım yoluyla miras aldığı tüm tiplerde görüntülenebilmesi durumudur. Örneğin;
public interface IAnimal
{
void MakeSound();
}
Yukarıdaki gibi hayvanı tanımlayan bir arayüz oluşturalım. Arayüz tek bir davranışa (Ses Çıkar) sahip olsun. Aşağıda ise bu arayüzü gerçekleştiren 3 sınıf tanımladık. Kedi, köpek ve köpekten türeyen Husky aynı arayüzü (IAnimal) gerçekleştiriyor.
internal class Cat : IAnimal
{
public void MakeSound()
{
Debug.WriteLine("Meoww");
}
}
internal class Dog : IAnimal
{
public virtual void MakeSound()
{
Debug.WriteLine("Woof..");
}
}
internal class Husky : Dog
{
public override void MakeSound()
{
Debug.WriteLine("Auwww");
}
}
Bunlara ek olarak hayvan arayüzünü içeren İnsan arayüzünü oluşturalım. İnsan arayüzü "hayvanı dürt" diye bir davranışa sahip. Bu arayüzü gerçekleştirdiğimiz abstract bir İnsan sınıfı ve bu sınıftan türeyen Köylü, Eskimo ve Mafya Babası sınıflarımız mevcut. Bu sınıfların ortak özelliği, bir veya daha fazla hayvana sahip olabilmeleri, yeni hayvan alabilmeleri ve bu hayvanları dürtebilmeleri şeklinde.
internal interface IHuman
{
void PokeAnimal();
}
internal abstract class Human : IHuman
{
private IList<IAnimal> Animals { get; set; }
protected Human()
{
Animals = new List<IAnimal>();
}
protected Human(IList<IAnimal> animals)
{
Animals = animals;
}
public virtual void BuyAnimal(IAnimal animal)
{
Animals.Add(animal);
}
public void PokeAnimal()
{
Debug.WriteLine($"I am a {GetType().Name}");
foreach (var animal in Animals)
{
Debug.WriteLine($"I poked my animal {animal.GetType().Name}.");
animal.MakeSound();
}
}
}
internal class Villager : Human
{
public Villager()
{
}
public Villager(IList<IAnimal> animals) : base(animals)
{
}
}
internal class Eskimo : Human
{
public Eskimo()
{
}
public Eskimo(IList<IAnimal> animals) : base(animals)
{
foreach (var animal in animals)
{
if (animal is Cat)
throw new NotSupportedException($"You can not buy {animal.GetType().Name}");
}
}
}
internal class GodFather : Human
{
public GodFather()
{
}
public GodFather(IList<IAnimal> animals) : base(animals)
{
}
}
Burada dikkat çekmek istediğim kısım, insan sınıfın sahip olduğu hayvanların, hayvan arayüzü listesi (IList<IAnimal>) olarak ilan edilmiş olmasıdır. Tüm hayvan sınıflarını, hayvan arayüzü görüntüsünde kullanarak polimorfizm sağlamaktayız. Peki ne işe yarayacak bu polimorfizm? İlerleyen kısımlarda daha iyi anlaşılacak.
internal class World
{
public World()
{
Humans = new List<IHuman>();
}
public List<IHuman> Humans { get; }
public void AddHuman(IHuman human)
{
Humans.Add(human);
}
}
Yukarıdaki sınıf da insanları barındıran sanal bir dünyayı tanımlamakta. Şimdi tanımlamış olduğumuz tüm bu arayüz ve sınıfları kullanacak olursak:
public class SampleRunner
{
public static void Run()
{
var world = new World();
world.AddHuman(new GodFather(new List<IAnimal>
{
new Cat(),
new Cat(),
new Dog(),
new Husky()
}));
world.AddHuman(new Eskimo(new List<IAnimal>
{
new Dog(),
new Husky()
}));
world.AddHuman(new Villager(new List<IAnimal>
{
new Cat(),
new Dog()
}));
foreach (var human in world.Humans)
{
human.PokeAnimal();
}
}
}
Bir dünya nesnesi oluşturduk.
Bu dünyaya;
2 kedi, 1 köpek ve 1 husky sahibi mafya babası,
1 köpek ve 1 husky sahibi eskimo,
1 kedi ve 1 köpek sahibi köylü ekledik.
Daha sonra bu insanların herbirinden sahip oldukları hayvanları dürtmelerini istedik.
Ortaya çıkan sonuç şu şekilde:
-------------------------------------------------------------------------
I am a GodFather
I poked my animal Cat.
Meoww
I poked my animal Cat.
Meoww
I poked my animal Dog.
Woof..
I poked my animal Husky.
Auwww
I am a Eskimo
I poked my animal Dog.
Woof..
I poked my animal Husky.
Auwww
I am a Villager
I poked my animal Cat.
Meoww
I poked my animal Dog.
Woof..
-----------------------------------------------------------------------------
Eğer polimorfizm kullanmasaydık, İnsan sınıfında her bir hayvan türü için ayrı bir liste alanı (IList<Cat>, IList<Dog> gibi) oluşturmamız gerekecekti. Ve her yeni eklediğimiz hayvan türü için insan sınıfı tanımını da değiştirmemiz gerekecekti. Benzer sorun insan türleri ve dünya sınıfı için de geçerli olacaktı.
Burada polimorfizm, sisteme daha fazla hayvan türü tanımladığımızda, insan sınıfında herhangi bir değişiklik yapmadan ve yine aynı şekilde daha fazla insan türü tanımladığımızda dünya sınıfında herhangi bir değişiklik yapmadan, bu nesnelere ait arayüzde belirttiğimiz davranışları (hayvan için ses çıkarma, insan için hayvanı dürtme), hayvan ya da insan türünü bilmemize gerek kalmadan gerçekleştirmemize olanak sağladı. Yazılımın tekrar kullanılabilirlik, sürdürülebilirlik, genişletilebilirlik, anlaşılabilirlik gibi kalite değerlerini de belli ölçüde yükseltmiş olduk.
Kaynak kodlara buradan ulaşabilirsiniz.