Property di Kotlin biasanya menyimpan nilai sendiri pada field di dalam class. Namun untuk kasus seperti inisialisasi tertunda, pencatatan audit, atau validasi nilai, pola get/set manual menjadi repetitif dan rentan kesalahan. Kotlin menyediakan property delegation yang memindahkan logika akses property ke objek lain lewat keyword by. Pada chapter ini kita akan membongkar konsep dasar delegation, melihat bagaimana compiler menerjemahkan by menjadi pemanggilan getValue/setValue, dan mempraktikkannya lewat dua delegate buatan sendiri. Pemahaman ini menjadi landasan bagi chapter-chapter berikutnya yang membahas lazy, observable, vetoable, hingga custom delegate.
Apa Itu Property Delegation #
Sebuah property didelegasikan ketika logika bacanya (get) dan tulisnya (set) dialihkan ke objek lain yang disebut delegate. Sintaksis dasarnya seperti berikut:
val x: Int by delegate
var y: String by delegateLainKompilator menerjemahkan val x by delegate menjadi pemanggilan delegate.getValue(thisRef, property). Untuk var y by delegateLain, penugasan y = "foo" diterjemahkan menjadi delegateLain.setValue(thisRef, property, "foo"). Karena itu, objek delegate tidak perlu tahu apa pun tentang property — cukup menyediakan dua operator function tersebut.
Kontrak formalnya didefinisikan oleh dua interface pada package kotlin.properties:
| Interface | Wajib pada | Cocok untuk |
|---|---|---|
ReadOnlyProperty<R, T> | getValue(thisRef, property): T | val |
ReadWriteProperty<R, T> | getValue + setValue(...) | var |
R adalah tipe receiver (biasanya class tempat property berada, atau Any? bila delegate generik), sedangkan T adalah tipe nilai yang dikeluarkan.
Delegate Sederhana Buku Sendiri #
Mari kita bangun dua delegate kecil untuk merasakan mekanismenya. File konsep_property_delegation.kt berisi class Konstan (read-only, mengembalikan nilai tetap) dan PencatatVar (read-write, mencatat jejak setiap perubahan):
// File: konsep_property_delegation.kt
// Mendemonstrasikan konsep property delegation: keyword `by` menyerahkan
// logika get/set ke objek delegate lain.
package com.example.delegasi
import kotlin.properties.ReadOnlyProperty
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.jvm.isAccessible
// Delegate sederhana: menyimpan nilai konstan.
class Konstan<T>(private val nilai: T) : ReadOnlyProperty<Any?, T> {
override fun getValue(thisRef: Any?, property: kotlin.reflect.KProperty<*>): T = nilai
}
// Delegate read-write yang mencatat setiap perubahan.
class PencatatVar<T>(initial: T) : ReadWriteProperty<Any?, T> {
private var nilai: T = initial
private val riwayat = mutableListOf<T>()
override fun getValue(thisRef: Any?, property: kotlin.reflect.KProperty<*>): T = nilai
override fun setValue(thisRef: Any?, property: kotlin.reflect.KProperty<*>, value: T) {
riwayat.add(nilai)
nilai = value
}
fun jejak(): List<T> = riwayat.toList()
}
class Aplikasi {
val versi: String by Konstan("1.0.0")
val tahun: Int by Konstan(2026)
var status: String by PencatatVar("idle")
}
fun main() {
val app = Aplikasi()
println("Versi: ${app.versi}")
println("Tahun: ${app.tahun}")
println("Status awal: ${app.status}")
app.status = "loading"
app.status = "ready"
println("Status akhir: ${app.status}")
// Akses delegate via KProperty.getDelegate(instance).
val statusProp = Aplikasi::status
statusProp.isAccessible = true
val delegasi = statusProp.getDelegate(app)
if (delegasi is PencatatVar<*>) {
println("Jejak perubahan status: ${delegasi.jejak()}")
}
// Demonstrasi: versi dan tahun memakai delegate Konstan yang sama jenisnya.
val versiProp = Aplikasi::versi
versiProp.isAccessible = true
val versiDelegate = versiProp.getDelegate(app)
println("Delegate versi (class): ${versiDelegate?.javaClass?.simpleName}")
}Output yang Dihasilkan:
Versi: 1.0.0
Tahun: 2026
Status awal: idle
Status akhir: ready
Jejak perubahan status: [idle, loading]
Delegate versi (class): KonstanMari kita bedah baris-baris penting pada kode di atas:
- Baris 11-13 (
class Konstan<T> : ReadOnlyProperty<Any?, T>): delegateval. Konstruktor menerimanilaidangetValueselalu mengembalikan nilai yang sama. Setiap propertyvalyang memakai delegate ini bersifat konstan — namun tetap berbeda denganconst valkarena nilainya baru dipegang saat instance dibuat, bukan dikompilasi sebagai konstanta literal. - Baris 16-28 (
class PencatatVar<T> : ReadWriteProperty<Any?, T>): delegatevar. Setiap kalisetValuedipanggil, nilai lama ditambahkan keriwayatsebelum diganti. Methodjejak()mengembalikan salinan list agar mutasi dari luar tidak mengganggu state internal. - Baris 30-35 (
class Aplikasi): tiga property yang memakai kedua delegate.versidantahunmemakaiKonstan, sedangkanstatusmemakaiPencatatVar. Inilah inti delegation — logika berada di satu tempat dan dipakai ulang oleh banyak property. - Baris 47-53 (akses delegate via reflection):
KProperty.getDelegate(instance)mengembalikan objek delegate di balik sebuah property. SetisAccessible = truediperlukan bila property tidakpublic. Setelah itu kita dapat memanggil method delegate sepertijejak()secara langsung. - Baris 56-59: demonstrasi serupa pada
versi. Output mencetak nama class delegate, membuktikan bahwaversidantahunmemakai instanceKonstanyang berbeda walaupun jenisnya sama.
Mengapa Memakai Delegation #
Tanpa delegation, kita akan menulis backing field plus getter/setter custom pada setiap property yang butuh perilaku khusus. Dengan delegation, perilaku tersebut dirangkum dalam satu class delegate yang dapat dipakai pada banyak property, bahkan lintas class. Standard library Kotlin memanfaatkan pola ini untuk lazy, Delegates.observable, Delegates.vetoable, dan map-backed property — keempatnya akan kita bahas pada chapter-chapter berikutnya.
Referensi Lanjutan #
- Delegated properties
— panduan resmi konsep property delegation dengan keyword
by - kotlin.properties package
— API reference paket
kotlin.propertiesberisi interface delegate
Selanjutnya #
Setelah memahami kontrak delegation, langkah berikutnya adalah memakai delegate paling umum di standard library — lazy — untuk inisialisasi tertunda yang hemat sumber daya. Materi tersebut akan kita bahas pada chapter lazy Delegation.