Kotlin'de Delegasyon
Bir class’ı extend ettiğimizde sub-class ve super-class arasında kırılgan bir bağımlılık oluşur. Bu bağımlılığın kırılgan olmasının sebebi super-class’ta yapılan değişikliklerin sub-class’ların çalışmasını bozabilme riskidir. Inheritance’ın bu yan etkisi yüzünden Kotlin’de class’lar final
‘dır (yani extend edilemezler). Eğer bir sınıfı genişletilebilir (extendable) yapmak istiyorsanız sınıfı open
olarak tanımlamanız gerekir. open
sınıflarda değişiklik yaparken bu değişikliklerden sub-sınıfların da etkilenebileceğini aklımızdan çıkartmamamız lazım.
Class Delegation
Bazen open
olmayan, yani extend etmeyi düşünmediğimiz sınıflara yeni özellikler eklemek isteyebiliriz. Böyle durumlarda Decorator
tasarım kalıbı uygulanabilir. Decorator tasarım kalıbı şöyle gerçeklenebilir:
- Yeni özellik eklemek istediğimiz orjinal sınıf ile aynı
interface
‘e sahip yeni bir sınıf oluşturulur. - Orjinal sınıfın bir instance’ı yeni sınıfa bir
field
olarak eklenir. - Değişmesini istediğimiz interface metodu dışındakı tüm metodlar orjinal sınıf instance’ına paslanır.
Aşağıda FilteringList adında bir MutableList
implementation’ı var. Bu listeye sadece bizim istediğimiz filtreye uygun elemanların girmesini istiyoruz. addXXX
metodlarını değiştirerek istediğimiz yeni özelliği ekleyebiliriz. Fakat MutableList interface’inde bulunan diğer metodlar için de orjinal listenin ilgili metodunu çağıran implementasyonlar eklememiz gerekiyor.
Yukarıdaki örnek Kotlin’de yazılmış olmasına rağmen bir sürü boilerplate
kod var. Neyse ki Kotlin compiler bizim için bu laf kalabalığı kodu otomatik olarak üretebiliyor. Bunun için class delagation kullanmamız gerekiyor. Kotlin’de bir interface’i implement ettiginizde, bu interface’in implementasyonunu by
keyword’u ile başka bir sınıfa delegate
edebilirsiniz.
Class delegation kullanıldığında FilteringList aşağıdaki gibi boilerplate
kodlardan arınmış oluyor.
FilteringList sınıfını aşağıdaki gibi kullanabiliriz:
Delagated Properties
Kotlin programla dilinde var
ile mutable val
ile immutable class property’leri tanımlayabiliriz. Property’leri tanımlarken optional olarak initializer
, getter
ve setter
kullanılabilir.
Property getter ve setter metodları karmaşık logic’ler içerebilir ve başka sınıflarda ve başka property’lerde yeniden kullanmak isteyebiliriz. Örneğin bir field’ın lazy
bir şekilde (getter ilk kez çağırıldığında) oluşturulması ya da bir field’in değeri değiştirildiginde (setter) istediğimiz bir kod bloğunun çalıştırılması gibi karmaşık işlemleri Delegated Properties
olarak yazıp reuse
edebiliriz.
Örneğin aşağıdaki kod parçası name property’sinin getter ve setter işlemlerinin LoggingDelegate
adında bir sınıf tarafından yapılacağını gösteriyor.
LoggingDelegate sınıfını Kotlin convention’larına göre aşağıdaki gibi yazabiliriz. Bu delegate sınıfı bir property’nin get/set metodları çağırıldığında işlemi konsola yazıyor:
Kotlin standard library’de yukarıda örnek olarak verilen LoggingDelegate’ten daha kullanışlı Delegate sınıfları var.
Delegates.vetoable
Property’nin değerini belirli bir kurala göre değiştirmek istediğimizde bu delegate’i kullanabiliriz. Örneğin User sınıfının age
property’si sadece pozitif tam sayılar alabiliyorsa aşağıdaki gibi bir vetoable
delegate kullanılabilir.
Delegates.observable
Bir property’nin değişimlerinden haberdar olmak istiyorsak observable
delegate kullanabiliriz. Örneğin:
lazy
Bazen bir propery’nin değerini hesaplamak masraflı bir işlem olabilir. Böyle durumlarda property değerinin ilk erişimde hesaplanması mantıklı olur. Böyle durumlarda lazy delegation
kullanılabilir. Aşağıdaki örnekte kullanıcının tüm satın almaları allPayments
lazy property’sine ilk kez erişildiğinde hesaplanıyor. Daha sonraki erişimlerde daha önce hesaplanan payment listesi kullanılır, database’e tekrar gidilmez.
Yukarıdaki örnekte kullanılan lazy delegation
thread-safe’tir. Eğer çalıştığınız ortamda birden fazla thread yoksa senkronizasyon maliyetleri ile uğraşmamak için alağıdaki gibi LazyThreadSafetyMode.NONE
kullanabilirsiniz.
Bir Kotlin yazısının daha sonuna geldik. Detaylara indikçe bu dili daha çok sevmeye başlıyorum :)