Polymorphism ve Dependency Injection

Geçen hafta yazılımcı arkadaşlarla iş görüşmeleri yaparken aklımıza geldi. Neredeyse her iş görüşmesinde soruyoruz; Nedir bu Polymorphism veya Dependency Injection. Görüşmeye gelenlerin %20’sinden cevap alıyoruz. Fakat biz de bu yabancı terimleri Türkçe ifade etmeye çalıştığımızda zorlandık, dilimiz dönmedi. Ya sürekli yabancı kaynak okumaktan ya da gerçekten Türkçe açıklamasının zor olduğundan. Aşağıda kısaca bu kavramları olabildiğince Türkçe anlatmaya çalışayım.

Polymorphism (Çok Biçimlilik)

Nesne yönelimli programlamada (Object Oriented Programming) birçok aynı özelliğe sahip nesnenin ortak özelliklerini bir arayüz veya soyut sınıf (Interface veya Abstract Class) ile belirtip, nesneleri bu arayüzden veya soyut sınıftan türetebiliyoruz. Bu özelliğe kalıtım (inheritence) diyoruz.

Aynı özelliğe sahip bu türetilmiş nesneleri, her nesnenin kendi tipi değil de türettiğimiz arayüz veya soyut sınıf tipi ile yani ortak özellikleri ile kullanırsak, bu özelliğe ait hangi nesne gelirse gelsin aynı kodun içinde kullanabiliyor, ata sınıfını kullanarakk aynı tipmiş gibi davranabiliyoruz. İşte buna Polymorphism deniyor.

En çok gerçek hayat örneği sanırım banka komponentleri için verilebilir. Diyelim ki Garanti Bankası ve Yapı Kredi Bankası POS işlemleri için sınıflarınız var. Her iki sınıfta da Sale (satış) ve InstallmentSale (Taksitli Satış) metodlarınız var. Eğer bunları bir Interface’den türetirseniz aşağıdaki gibi bir yapı elde edersiniz;

public interface IBank
{
public int Sale();
public int InstallmentSale();
}

public class GarantiBankasiPos : IBank
{
public int Sale()
{
// sale kodu buraya
}
public int InstallmentSale()
{
// InstallmentSale kodu buraya
}
}

Ortalığı karıştırmamak için metod parametrelerini ve içindeki kodu yazmadım. Yukarıdaki yapıdaki her banka pos sınıfı için Sale() metodunu kodladığım durumda aşağıdaki gibi bir kodla bankadan bağımsız satış yapabilir hale gelirim;


public int DoSale(IBank bank, parametreler ....)
{
// parametre kontrolleri ve diğer iş kuralları uygulama kodu
return bank.Sale(parametreler ...);
}

İşte burada Polymorphism uygulamış olduk. Banka tipinden bağımsız olarak kontrollerimizi gerçekleştirip satışı tek metod üzerinden yapabiliyoruz. Bu bizi kod tekrarından korudu, kodumuzu basitleştirip bakım ve yeni pos sınıfları eklememizi kolaylaştırdı. Artık aynı şekilde ekleyeceğimiz her pos sınıfını IBank’tan türeterek aynı kodun içine referans olarak verdiğimizde o banka ile işlem yapabileceğiz.

Dependency Injection (Bağımlılık Enjeksiyonu)

Bağımlılık Enjeksiyonu, Dependency Injection’un birebir çevirisi olduğu için kullandım. Aslında şimdiye kadar geçen terimlerin Türkçe’sini günlük hayatta hiç kullanmıyoruz. Herkes Dependency Injection veya DI olarak, Polymorphism, Interface, Abstract Class olarak bu kavramları kullanıyor.

Peki Dependency Injection nedir? Dependency Injection, bir sınıfın içindeki farklı görevleri, o sınıfa dışarıdan parametrik olarak verebilmektir. Yani iş kuralları olan sınıfımın içinde veritabanı işlerini yapmayıp, bu işlevi veritabanı yardımcı sınıfı olarak ayırıp, referansını iş kuralları sınıfıma parametrik olarak geçebilirim. Örneğin;

public class PaymentManager
{
private ILogger _logger;

public PaymentManager(ILogger logger)
{
_logger = logger;
}

public void DoPayment()
{
// DoPayment iş kuralları kodu
_logger.Log("Ödeme Yapıldı");
}
}

Yukarıdaki örnekte ILogger tipindeki işi sadece log almak olan bir sınıfın referansını, PaymentManager sınıfına, constructordan parametrik olarak geçtik. Burada hem loglama ile ilgili kodlamayı PaymentManager gibi görevi bambaşka birşey olan bir sınıf içinde yazmadık hem de bu sınıfı loglama sınıfından tamamen bağımsız hale getirdik. Yani artık aynı görevi yapan başka bir loglama sınıfını da buraya verip istersem başka bir ortama loglama yaptırabilirim.

Dependency Injection yöntemi işinize bağlı olarak birçok şekilde kullanılabiliyor. Enjekte edeceğiniz sınıfı constructor’dan veya fonksiyon’dan parametre geçebilir, mevcut sınıfa property olarak tanımlayabilir veya mevcut sınıfın atasına property olarak tanımlayabilir ve bu şekilde kullanabilirsiniz.

DI, en çok TDD (Test Driven Development) yöntemleri ile birlikte kullandığımız bir yöntem. Özellikle test edeceğimiz kısmı, rahat test edebilmek için diğer kısımlardan izole ediyoruz. Ayrıca dışarıdan o tipte herhangi başka bir sınıf da enjekte edebileceğimiz için Mock veya Fake denilen yapılar ortaya çıkmış. Yani daha henüz Logger sınıfı yazmadınız fakat bunun görevini yapan sahte bir sınıfı içeri verip Logger gibi davranmasını sağlayıp, işin o kısmıyla uğraşmıyorsunuz. Test etmeniz gereken yeri test edip daha sonra uygulama zamanında gerçek logger sınıfınızı enjekte ediyorsunuz. Böylece testleriniz daha hızlı çalışıyor. TDD’de her yaptığınız değişiklikte bütün testleri çalıştırmanız gerektiği için bu önemli. Fakat bu başka bir blog’un konusu.

Toparlayıp birer cümlede bu iki kavramı aşağıdaki gibi tanımlayabiliriz;
Polymorphism: Aynı özellikleri ile bir ataya bağlayabildiğimiz sınıfların ortak özelliklerini, başka bir kod parçası içinde, aynı tipe aitmiş gibi o atadan türeyen bütün sınıflar için kullanabilmek.
Dependency Injection: Bir sınıfın içindeki görevleri mantıklı parçalara ayırarak, bu parçaları o sınıfa dışarıdan polimorfik bir yapıda parametre olarak geçebilmek ve böylece bağımlılığı ortadan kaldırmak.

Kısaca Polymorphism ve Dependency Injection kavramlarını anlatmaya çalıştım.