Kotlin Delegation By Muhammet Küdür

Muhammet Küdür
3 min readSep 11, 2023

--

Herkese merhabalar, yeni bir yazı ile tekrar karşınızdayım. Bu yazımda Kotlin’de Delegation neden kullanılır, ne tür özellikleri vardır bunlardan elimden geldiğince bahsedeceğim. Umarım faydalı bir yazı olur.

Kısaca ‘Delegation’ “İt ite buyurur, it de kuyruğuna buyurur” atasözünün programlama literatürüne geçmesiyle ortaya çıkmış bir olaydır. Yani bir nesnenin yaptığı bir işi başka bir nesneye aktarmaktır. Örneğin elimizde 2 farklı sınıf olsun A ve B sınıfları. B Sınıfının; A’ya verilerek A sınıfı içerisinde ‘kendisine ait bir şey çağırmasının yetkisinin verilmesine’ Delegation denir.

Delegation Explicit(açık) ve Implicit(örtülü/kapalı) olarak iki farklı şekilde yapılabilir.

1)Explicit Delegation

Kod üzerinden Explicit olarak Delegation nasıl yapılır buna bakalım. Daha iyi anlatabilmek için Implicit Delegation için de aynı örneği kullanacağım. Böylece aradaki farkı daha iyi görebiliriz.

interface Greeting {
fun sayHello()
}

class EnglishGreeting : Greeting {
override fun sayHello() {
println("Hello!")
}
}

class SpanishGreeting : Greeting {
override fun sayHello() {
println("¡Hola!")
}
}

class Greeter(val greeting: Greeting) {
fun greet() {
greeting.sayHello()
}
}

fun main() {
val englishGreeting = EnglishGreeting()
val spanishGreeting = SpanishGreeting()

val greeter1 = Greeter(englishGreeting)
val greeter2 = Greeter(spanishGreeting)

greeter1.greet() // English: Hello!
greeter2.greet() // Spanish: ¡Hola!
}

Gördüğümüz üzere normalde selamlama işlemini Greeter classının içerisinde yapmamız gerekirken bu işlem yaptığımız işi primary constructor’da aldığımız Greeting interface’ine vererek bu interface’i implement etmiş olan herhangi bir class’a devretmemize olanak sağladı(Interface programming).

Bunu Implicit olarak yapsaydık neler olurdu? Buna bakalım:

2) Implicit Delegation

interface Greeting {
fun sayHello()
}

class EnglishGreeting : Greeting {
override fun sayHello() {
println("Hello!")
}
}

class SpanishGreeting : Greeting {
override fun sayHello() {
println("¡Hola!")
}
}
// Implicit Delegation
class Greeter(val greeting: Greeting) : Greeting by greeting

fun main() {
val englishGreeting = EnglishGreeting()
val spanishGreeting = SpanishGreeting()

val greeter1 = Greeter(englishGreeting)
val greeter2 = Greeter(spanishGreeting)

greeter1.sayHello() // English: Hello!
greeter2.sayHello() // Spanish: ¡Hola!
}

Implicit Delegation’da ‘by’ anahtar kelimesiyle Delegate işlemini gerçekleştirmiş oluyoruz.

Burada artık Greeting interface’ini implement etmiş herhangi bir class ile bu parametre üzerinden Greeter’ın bir instance’ını oluşturabilir ve sayHello() fonksiyonuna direkt olarak erişim sağlayabiliriz.

Implicit olarak yaptığımız Delegation’da Greeter class’ı içerisinde tekrar bir member function oluşturmak zorunda kalmadık. IDE direkt olarak Delegation yöntemiyle “sayHello()” fonksiyonunu çağırmak istediğimizi anladı.

Bu sayede her seferinde Delegation yapmak istediğimizde tekrar tekrar member function oluşturma zahmetinden kurtulmuş olduk. Kod tekrarına düşmedik.

Bu örnekler üzerinden tamam da kardeşim, bunun yerine ben direkt yazar geçerim bu beni hangi dertten kurtardı şimdi?! Demiş olabilirsiniz(ben dedim şahsen).

Delegation kullanımına kişisel projelerimizde ihtiyaç duymuyor olabiliriz. Ancak; örneğin profesyonel hayatta yüzlerce classın yazıldığı büyük bir projede çalıştığımızı düşünelim. Miras aldığımız her fragment da loglama işlemi yaptığımız bir BaseFragment() classımız olsun.

abstract class BaseFragment() : Fragment(){
// some operations
fun log(message:String){
println(message)
}
}
class HomeFragment(): BaseFragment(){
// some operations
override fun onViewCreated(){
// some operations
log("Hello Muhammet") // output: Hello Muhammet!
}
}

Buraya kadar bir sıkıntı yok. Fakat ileride projemiz büyüdükçe loglama yapmamamız gereken ya da loglama yapmak istemediğimiz Fragmentlarımız olabilir. Bununla birlikte projenin boyutuna göre BaseFragment’ı kalıtım alan yüzlerce fragment’ımız olmuş olabilir, BaseFragment’a olan bağımlılıktan dolayı bu sorunu kolayca çözemeyiz.

Her şeyi Base yapıya yazmak beraberinde sorunlar getirebilir. Bunun yerine loglama işlemini Delegate edersek hem BaseFragment’ımızın şişmesini, bir God Class’a dönüşmesini önlemiş oluruz hem de istemediğimiz Fragmentlarda loglama yapmayız. Bu sebeplerden ötürü yapıyı şu şekilde değiştirelim;

interface Logger{
fun log(message:String)
}

class LoggerImpl : Logger{
override fun log(message:String) {
println(message)
}

}

abstract class BaseFragment() : Fragment(){
// some operations
}

class HomeFragment(): BaseFragment(), Logger by LoggerImpl(){
// some operations
override fun onViewCreated(){
// some operations
log("Hello Muhammet") // output: Hello Muhammet!
}
}

Bu sayede BaseFragment da her seferinde yapmamamız gereken ya da yapmak istemediğimiz bir işlemi Logger’a devrettik. Ve sorunu çözdük.

--

--