Selasa, 14 Juni 2022

Belajar Property Delegation di Kotlin


Property Delegation

Pengelolaan properti kelas baik itu memberikan atau merubah sebuah nilai dapat didelegasikan kepada kelas lain. 
Dengan ini kita dapat meminimalisir boilerplate dalam penulisan getter dan setter (jika properties menggunakan var) pada setiap kelas yang kita buat. Sebagai contoh, kita memiliki tiga buah kelas yang di dalamnya memiliki satu properti String.
Jika kita ingin menerapkan getter dan setter pada setiap properti kelasnya, maka kita perlu menuliskan getter dan setter tersebut pada seluruh kelas. Hal tersebut dapat mengurangi efisiensi dalam menuliskan kode karena terlalu banyak kode yang harus kita tulis secara berulang. 
Solusinya, kita perlu membuat sebuah kelas yang memang bertugas untuk mengatur atau mengelola fungsi getter dan setter untuk sebuah properti kelas. Teknik tersebut pada Kotlin dinamakan Delegate.
Sebelum mendelegasikan sebuah properti kita perlu membuat kelas delegasi terlebih dahulu. Mari kita buat sebuah kelas delegasi.

  1. import kotlin.reflect.KProperty

  2.  

  3.  

  4. class DelegateName {

  5.     private var value: String = "Default"

  6.  

  7.     operator fun getValue(classRef: Any?, property: KProperty<*>) : String {

  8.         println("Fungsi ini sama seperti getter untuk properti ${property.name} pada class $classRef")

  9.         return value

  10.     }

  11.  

  12.     operator fun setValue(classRef: Any?, property: KProperty<*>, newValue: String){

  13.         println("Fungsi ini sama seperti setter untuk properti ${property.name} pada class $classRef")

  14.         println("Nilai ${property.name} dari: $value akan berubah menjadi $newValue")

  15.         value = newValue

  16.     }

  17. }



Kemudian untuk mendelegasikan sebuah properti kelas, kita gunakan keyword by dalam menginisialisasi properti tersebut kemudian diikuti dengan namanya. Perhatikan kode berikut:

  1. class Animal {

  2.     var name: String by DelegateName()

  3. }



Dengan begitu nilai properti name dikelola melalui kelas DelegateName. Kita dapat mendelegasikan banyak properti yang terdapat pada banyak kelas kepada satu kelas Delegate saja. Perhatikan kode berikut untuk untuk lebih jelasnya:

  1. class Animal {

  2.     var name: String by DelegateName()

  3. }

  4.  

  5. class Person {

  6.     var name: String by DelegateName()

  7. }

  8.  

  9. class Hero {

  10.     var name: String by DelegateName()

  11. }



Mari kita membuat sebuah objek, ubah dan akses nilai propertinya pada setiap kelas, kemudian jalankan. Maka hasilnya akan seperti pada kode berikut:
  1. fun main() {
  2.     val animal = Animal()
  3.     animal.name = "Dicoding Miaw"
  4.     println("Nama Hewan: ${animal.name}")
  5.  
  6.     val person = Person()
  7.     person.name = "Dimas"
  8.     println("Nama Orang: ${person.name}")
  9.  
  10.     val hero = Hero()
  11.     hero.name = "Gatotkaca"
  12.     println("Nama Pahlawan: ${hero.name}")
  13. }
  14.  
  15. /*
  16. output:
  17.     Fungsi ini sama seperti setter untuk properti name pada class Animal@17f052a3
  18.     Nilai name dari: Default akan berubah menjadi Dicoding Miaw
  19.     Fungsi ini sama seperti getter untuk properti name pada class Animal@17f052a3
  20.     Nama Hewan: Dicoding Miaw
  21.     Fungsi ini sama seperti setter untuk properti name pada class Person@2e0fa5d3
  22.     Nilai name dari: Default akan berubah menjadi Dimas
  23.     Fungsi ini sama seperti getter untuk properti name pada class Person@2e0fa5d3
  24.     Nama Orang: Dimas
  25.     Fungsi ini sama seperti setter untuk properti name pada class Hero@5010be6
  26.     Nilai name dari: Default akan berubah menjadi Gatotkaca
  27.     Fungsi ini sama seperti getter untuk properti name pada class Hero@5010be6
  28.     Nama Pahlawan: Gatotkaca
  29. */

Pada contoh di atas, delegasi hanya dapat digunakan oleh properti yang memiliki tipe data String. Namun kita juga dapat membuat sebuah delegasi kelas umum yang dapat digunakan oleh seluruh tipe data dengan memanfaatkan tipe data Any.
  1. class DelegateGenericClass {
  2.     private var value: Any = "Default"
  3.  
  4.     operator fun getValue(classRef: Any, property: KProperty<*>): Any {
  5.         println("Fungsi ini sama seperti getter untuk properti ${property.name} pada class $classRef")
  6.         return value
  7.     }
  8.  
  9.     operator fun setValue(classRef: Any, property: KProperty<*>, newValue: Any) {
  10.         println("Nilai ${property.name} dari: $value akan berubah menjadi $newValue")
  11.         value = newValue
  12.     }
  13. }
  14.  
  15. class Animal {
  16.     var name: Any by DelegateGenericClass()
  17.     var weight: Any by DelegateGenericClass()
  18.     var age: Any by DelegateGenericClass()
  19. }
Kemudian mari kita membuat sebuah objek dari kelas Animal, ubah dan akses nilai propertinya kemudian jalankan. Maka hasilnya akan seperti pada kode berikut:
  1. fun main(){
  2.     val animal = Animal()
  3.     animal.name = "Dicoding cat"
  4.     animal.weight = 6.2
  5.     animal.age = 1
  6.  
  7.     println("Nama: ${animal.name}")
  8.     println("Berat: ${animal.weight}")
  9.     println("Umur: ${animal.age} Tahun")
  10. }
  11.  
  12. /*
  13. output:
  14.     Nilai name dari: Default akan berubah menjadi Dicoding cat
  15.     Nilai weight dari: Default akan berubah menjadi 6.2
  16.     Nilai age dari: Default akan berubah menjadi 1
  17.     Fungsi ini sama seperti getter untuk properti name pada class Animal@17f052a3
  18.     Nama: Dicoding cat
  19.     Fungsi ini sama seperti getter untuk properti weight pada class Animal@17f052a3
  20.     Berat: 6.2
  21.     Fungsi ini sama seperti getter untuk properti age pada class Animal@17f052a3
  22.     Umur: 1 Tahun
  23. */

Perhatikan kode diatas, kita telah memberikan nilai pada setiap properti dengan tipe data yang berbeda. Tetapi dengan DegelateGenericClass(), pengelolaan properti dapat digunakan pada seluruh tipe data properti

Posting Komentar