Arayüz Ayrımı Prensibinin odak noktası; eğer bir sınıf implement ettiği interface’e ait tüm nesneleri kullanmıyor ya da o interface ilgili sınıf için eksik kalıyor ise ortak metodları içeren bir arayüz oluşturup, farklılaştığı noktalar için ise yeni arayüzler oluşturulmalı ve artık bu yeni interface kullanılmalıdır.
Bu sayede nesne yönetimimizi kolaylaştırması için kullanmamız gereken interface’in hatalı uygulamalar nedeniyle ortaya çıkartacağı olası karmaşıklıkların önüne geçebiliriz. Şimdi bunu örnek bir senaryo üzerinde kavrayalım;
IVehicle adında bir arayüzümüz (interface) olduğunu ve bu interface implement eden Airplane ve Train sınıflarımız olduğunu düşünelim. IVehicle interface (arayüz) içerisinde closeDoors ve doFly metodumuz olursa;
Airplane sınıfı için doFly metodu uygulanabilir, fakat Train :/ Trenler uçamaz… (henüz, 2021) Bu durumda Train sınıfı içerisinde doFly metodu için NotImplementedException fırlatabiliriz fakat bu iyi bir çözüm olmaz…
Eğer closeDoors için değerlendirecek olursak, karşımıza bir sorun çıkmaz çünkü uçak ve tren için kapıları kapatma eylemi uygulanabilir durumdadır. Yani interface içerisinde yer alan tüm metodlar implement edildikleri sınıflar için kullanılabilir durumdadır.
Peki doğru çözüm nedir?
Ortak noktaları kapsayacak metodlara sahip arayüzler (interfaces) oluşturmak ve ayrıştıkları noktalar için yeni arayüzler (interfaces) oluşturmak gerekir. Yani doğru çözümümüz şu şekilde olacaktır;
IVehicle interface içerisinde yalnızca closeDoors metodu bulunur. Çünkü ortak noktaları kapılarının olması ve kapatılabilir olmasıdır. Airplane için ise IFlyable adında bir interface (arayüz) oluşturup, içerisinde doFly metodunu tanımlayıp bunu implement etmeliyiz. (closeDoors metodunu miras almak için IFlyable, IVehicle’dan türetilmelidir)
Doğru çözüm ile herhangi bir aracın uçabilir olup olmadığını kontrol etmek için ise IFlyable interface’inden türeyip/türemediğini kontrol etmemiz yeterli olacak ve IVehicle interface referans aldığımız bir yerde Airplane ya da Train kullanılabilecektir.
Faydası ne oldu?
Eğer arayüz ayrımını doğru şekilde yapmasaydık ve örneğimizin başındaki gibi bir arayüz kullanıp sonrasında onu implement ettiğimiz sınıflarda doFly için NotImplementedException fırlatsaydık, bu metodu kullanmak istediğimiz her yerde exception handling yapmamız gerekirdi hatta olası akış bozukluklarına (yarıda kesilme, eksik tamamlanma) sebep olabilirdik. Bu prensibi dikkate alarak uyguladığımız iyi çözümde ise IFlyable interface kontrol edeceğimizden olası hataların önüne geçmiş olduk ve mimari açıdan çok daha doğru bir yapı kurmuş olduk.
Interface’leri yalnızca kullanmış olmak için kullanıp sonradan başımıza bela etmemek, gerçekten sürdürülebilir projeler geliştirebilmek için arayüzlerimizi (interfaces) dikkatli kullanalım, kullanmayan arkadaşlarımızı uyaralım, PR’larını Approve etmeyelim, geceleri kabusları olalım 🙂 Interfaceler ile aranızdan suların sızmadığı temiz projelerde görüşmek dileğiyle…