Kotlin OOP: Mengenal Getter dan Setter

Getter dan Setter merupakan 2 fitur Kotlin yang berhubungan dengan Properti. Dengan ini kita bisa menggubah perilaku properti dari sebuah kelas. Mari kita bahasa satu per satu.

Backing Field

Sebelum membahas getter dan setter alangkah baiknya kita mengenal dulu backing field. Pada Kotlin, Backing field merupakan bagian dari properti yang menyimpan nilai dari properti.

Saat kita mengakses nilai dari properti, maka akan diberikan nilai dari backing field milik properti. Ini adalah getter bawaan dari properti. Saat kita menentukan (mengubah) nilai dari properti, maka nilai dari backing field milik properti akan diubah menjadi nilai yang ditentukan. Ini adalah setter bawaan dari properti.

Getter

Getter merupakan fungsi yang menentukan nilai yang diberikan saat nilai suatu properti diakses. Fungsi yang dijadikan getter harus diberi nama get. Getter harus dideklarasikan di bawah properti.

Getter bisa digunakan pada properti mutable (var) maupun immutable (val). Karena nilai dari kedua properti tersebut sama-sama bisa diakses.

Berikut adalah contohnya:

class Orang(var namaAwal: String, var namaAkhir: String) {
    val namaPanjang: String
        get() {
            println("Getter namaPanjang dipanggil")
            return "$namaAwal $namaAkhir"
        }
}

Fungsi yang di sorot adalah getter dari properti namaPanjang.

Saat nilai dari namaPanjang diakses maka kode di dalam get() akan dipanggil dan akan diberikan nilai yang dikembalikan fungsi get(). Dengan kata lain nilai dari dari namaPanjang akan selalu "$namaAwal $namaAkhir".

Contoh penggunaan adalah seperti ini:

val orang = Orang("Ibnu", "Umar")
println(orang.namaPanjang)
orang.namaAwal = "Toni"
orang.namaAkhir = "Awal"
println(orang.namaPanjang)

/*
Getter namaPanjang dipanggil
Ibnu Umar
Getter namaPanjang dipanggil
Toni Awal
*/

Kita juga dapat membuat fungsi Getter di atas menjadi lebih ringkas dengan menggunakan single expression function. Jadinya seperti ini:

class Orang(var namaAwal: String, var namaAkhir: String) {
    val namaPanjang: String
        get() = "$namaAwal $namaAkhir"
}

Setter

Setter merupakan fungsi yang dipanggil saat suatu properti nilainya diubah. Dengan ini kita bisa mengubah nilai properti jika nilai properti lain berubah. Fungsi yang dijadikan setter harus diberi nama set. Pada setter terdapat 1 parameter yang berisi nilai yang diberikan kepada properti.

Setter hanya bisa digunakan pada properti mutable (var). Karena hanya properti jenis ini yang nilainya dapat diubah.

Berikut adalah contohnya:

class Orang(var namaAwal: String, var namaAkhir: String) {
    var namaPanjang: String = "$namaAwal $namaAkhir"
        set(value) {
            val namaSplit = value.split(" ", limit = 2)
            namaAwal = namaSplit[0]
            namaAkhir = namaSplit[1]
        }
}

Pada contoh di atas saat nilai dari properti namaPanjang diubah maka nilai nilai dari properti namaAwal dan namaAkhir juga ikut berubah. Parameter value pada setter berisi nilai yang diberikan kepada properti namaPanjang. Kata pertama di namaPanjang dianggap sebagai nama awal dan sisanya dianggap nama akhir.

Fungsi split digunakan untuk memecah String menjadi Array menggunakan delimiter . split(" ", limit = 2) akan memecah String menggunakan spasi sebagai delimiter dan membatasi hasilnya menjadi 2.

Berikut penggunaannya:

val orang = Orang("Ibnu", "Abbas")
println(orang.namaAwal) // Ibnu
println(orang.namaAkhir) // Abbas
orang.namaPanjang = "Sunan Ampel"
println(orang.namaAwal) // Sunan
println(orang.namaAkhir) // Ampel
println(orang.namaPanjang) // Ibnu Abbas

Pada baris kode terakhir terlihat jika nilai dari namaPanjang tidak berubah. Kenapa bisa begitu?. Padahal pada baris kode sebelumnya kita mengubah nilai namaPanjang.

Masalah ini disebabkan karena pada setter kita tidak mengubah nilai dari backing field. Padahal saat kita mengakses nilai dari namaPanjang akan diberikan nilai dari backing field milik namaPanjang. Pada saat mendeklarasikan setter kita memiliki tanggung jawab untuk mengubah backing field.

Nilai dari backing field hanya bisa diubah dari dalam setter dengan cara menentukan nilai dari field. Untuk mengatasi permasalahan di atas, tambahkan kode berikut ke baris setter yang terakhir:

        set(value) {
            // ...
            field = value
        }

Kita bisa coba lagi:

val orang = Orang("Ibnu", "Abbas")
orang.namaPanjang = "Sunan Ampel"
println(orang.namaPanjang) // Sunan Ampel

Ada satu permasalahan lagi contoh di atas. Permasalahannya adalah saat kita mengubah nilai dari namaAwal atau namaAkhir, nilai namaPanjang tidak berubah.

println(orang.namaPanjang) // Ibnu Abbas
orang.namaAwal = "Raden"
println(orang.namaPanjang) // Ibnu Abbas

Untuk mengatasi permasalahan seperti itu, kita bisa menggunakan getter dan setter secara bersamaan.

Menggunakan Getter dan Setter Bersamaan

Getter dan Setter juga bisa digunakan secara bersamaan. Getter dan Setter hanya bisa digunakan secara bersamaan pada variabel mutable (var).

Berikut penerapannya untuk mengatasi permasalahan pada contoh sebelumnya:

class Orang(var namaAwal: String, var namaAkhir: String) {
    var namaPanjang: String
        get() = "$namaAwal $namaAkhir"
        set(value) {
            val namaSplit = value.split(" ", limit = 2)
            namaAwal = namaSplit[0]
            namaAkhir = namaSplit[1]
        }
}

Pada contoh tersebut, kita tidak perlu mengubah backing field pada setter. Karena saat kita mengakses nilai dari namaPanjang, nilai yang diberikan bukan nilai dari backing field tetapi nilai dari getter.

Berikut contoh penggunaan:

val orang = Orang("Jovana", "Michael")
println(orang.namaPanjang) // Jovana Michael
orang.namaAwal = "Raditya"
orang.namaAkhir = "Dika"
println(orang.namaPanjang) // Raditya Dika

orang.namaPanjang = "Anggiat Sahat"
println(orang.namaAwal) // Anggiat
println(orang.namaAkhir) // Sahat
println(orang.namaPanjang) // Anggiat Sahat