ProgramlamaOrta/Kıdemli Kotlin Geliştirici

Kotlin'da arayüzler üzerinden davranış delege etme (delege etme arayüzü) nasıl çalışır? Ne zaman kullanılmalıdır, özellik delege etmeden ve klasik mirastan farkı nedir?

Hintsage yapay zeka asistanı ile mülakatları geçin

Cevap.

Kotlin'de davranış delege etme, sınıfın imzasında doğrudan by anahtar kelimesi ile gerçekleştirilen bir dil mekanizmasıdır. Bu, arayüzdeki (veya birden fazla arayüzdeki) yöntem çağrılarını başka bir nesneye, uygulanmasına otomatik olarak iletmekte, boilerplate’i azaltmakta ve kompozisyonu kolaylaştırmaktadır.

Sorunun Geçmişi

Arayüz delege etmenin ortaya çıkışı, çoklu mirasın sınırlamalarını ve dezavantajlarını ortadan kaldırma girişimidir. Bu, "inheritance yerine composition" fikridir – davranışı sınıf hiyerarşisine başvurmadan devrediyoruz. Kompozisyonun daha yaygın olduğu dillerden (örneğin; Go, Scala) ödünç alınmıştır.

Problem

Java ve diğer dillerde, genellikle bir arayüz oluşturmak ve her yöntemi manuel olarak uygulamak zorunda kalındığı için, hızla eskiyen bir yaklaşım. (Object Adapter deseni)

Çözüm

Kotlin, arayüzü by kullanarak deklaratif bir şekilde delege etme olanağı sunar:

interface Logger { fun log(msg: String) } class ConsoleLogger: Logger { override fun log(msg: String) = println(msg) } class Service(logger: Logger): Logger by logger { fun doWork() { log("İş başladı") // ... } } val service = Service(ConsoleLogger()) service.doWork()
  • Tüm Logger yöntemleri, sağlanan logger nesnesi aracılığıyla uygulanır ve Service sınıfında yöntemleri açıkça yeniden tanımlamak veya proxylemek gerekmez.

Ana özellikler:

  • Arayüz uygulamasını kullanımdan ayırır, kod tekrarını azaltır
  • Delege etme, mirastan daha esnektir ve birçok davranışla çalışabilir
  • SOLID en iyi uygulamalarını destekler

Zorlayıcı Sorular.

Service sınıfına aynı imzaya sahip kendi arayüz yöntemini eklerseniz ne olur?

Kendi uygulamanız "delege edilen" yöntemini "geçersiz kılar" – yani, sınıfta açıkça tanımlanan yöntem baskın gelir:

class Service(logger: Logger): Logger by logger { override fun log(msg: String) = println("ÖN EK: $msg") }

Bir sınıf, birden fazla arayüzü farklı nesnelere delege edebilir mi?

Evet, bir sınıf birden fazla arayüzü farklı nesnelere uygulayıp delege edebilir, ancak her arayüz bir nesneye delege edilir:

class Service( logger: Logger, tracker: Tracker ): Logger by logger, Tracker by tracker

Arayüz delege etme ile by kullanarak özellik delege etme arasındaki fark nedir?

  • Arayüz delege etme, arayüzün tüm fonksiyonlarının uygulanmasını başka bir nesneye iletir.
  • Özellik delege etme, belirli bir türdeki (ReadOnlyProperty, ReadWriteProperty) delege nesnesine get/set ile ilgili çalışmaları delege eder.

Tipik Hatalar ve Anti-Desenler

  • Çok büyük arayüzlerin delege edilmesi (ISP ihlali)
  • Açık uygulama ve delege etmenin aynı anda uygulanması (beklenmedik davranış)
  • Delege etme ile mirası bir üst sınıf ile birleştirmeye çalışırken yöntemlerin çözüm sırasını yok sayma

Gerçek Hayattan Bir Örnek

Olumsuz Durum

Sınıf, arayüzü manuel olarak uyguluyor, her yöntemi delege çağırıyor, yeni yöntemler eklenince proxy güncellemeyi unutuyor, bu da hatalara yol açıyor.

Artılar:

  • Mantık açıkça kontrol ediliyor

Eksiler:

  • Yüksek hata riski, boilerplate
  • Arayüz büyüdükçe kötü ölçekleniyor

Olumlu Durum

Dil delege etmesi kullanılıyor, yalnızca standart dışı yöntemler sınıf içinde uygulanıyor, yeni işlevsellik büyük değişiklikler olmadan ekleniyor.

Artılar:

  • Minimum kod
  • Genişleme noktaları üzerinde net kontrol

Eksiler:

  • Kombine uygulama sırasında dikkat gerektirir (delege edilen yöntemi kendi uygulamanızla kolayca gölgede bırakabilirsiniz)