Pengenalan Konsep R6 Class di R: Public, Private, dan Method

By | October 25, 2026
58 Views

Kode yang mulai rumit sering menyulitkan proses perawatan (maintenance). Jika kita sering menggunakan R, biasanya kita menulis banyak fungsi. Seiring bertambahnya kebutuhan, fungsi-fungsi tersebut bisa saling bergantung dan data yang digunakan harus dikirim berulang kali sebagai argumen.

Konsep class di R sangat jarang diajarkan oleh lembaga tutorial karena mereka fokus kepada functional programming saja, padahal kalau olah data yang enteprise udah sangat rumit bahkan permintaan penyajian datanya makin banyak, sehingga kalau buat function terlalu banyak malah merepotkan. Mengapa demikian? karena ada beberapa function itu sifatnya unik (hanya dipakai oleh hal tertentu saja) sehingga saya menyembunyikan nya didalam method private saja. Sebenarnya walaupun bisa disiasati dengan inner function tapi kok terlalu rumit buat merawat kode tersebut.

Library Class di R sangat banyak, namun saya lebih suka menggunakan R6 karena lebih mirip bahasa Java, C#, bahkan lebih canggih daripada python karena python tidak mengenal konsep private lho. Konsep Class tidak cocok bagi kalian yang hanya mengolah dataset yang kecil dan tidak saling terhubung apalagi kalau cuman dataset yang siap pakai. Jangan dibandingkan dengan dataset perusahaan besar yang kadang membutuhkan banyak pre pengolahan.

Salah satu cara untuk merapikan pola seperti ini adalah menggunakan sistem kelas R6. R6 memungkinkan kita mengelompokkan data dan fungsi yang mengolah data tersebut dalam satu objek. Tutorial ini mengenalkan konsep dasarnya melalui contoh sederhana.

1. Memasang dan memuat paket

Jika paket R6 belum tersedia, pasang terlebih dahulu:

install.packages("R6")

Kemudian muat paketnya:

library(R6)

2. Membuat kelas pertama

Misalkan kita ingin membuat objek untuk menyimpan informasi seseorang. Objek ini memiliki data nama dan umur, serta metode untuk menyapa.

Orang <- R6Class(
  "Orang",
  public = list(
    nama = NULL,
    umur = NULL,

    initialize = function(nama, umur) {
      self$nama <- nama
      self$umur <- umur
    },

    sapa = function() {
      paste("Halo, nama saya", self$nama)
    }
  )
)

R6Class() mendefinisikan cetak biru kelas. Bagian public berisi anggota yang dapat diakses dari luar objek, termasuk data (sering disebut field) dan fungsi milik objek (disebut method). initialize() dijalankan saat objek dibuat. Kata self merujuk pada objek yang sedang digunakan.

See also  Positron - Lingkungan Modern untuk Analisis Data Menggunakan R

3. Membuat dan menggunakan objek

Kelas adalah cetak birunya; untuk menggunakannya kita membuat sebuah objek atau instance:

andi <- Orang$new("Andi", 25)

andi$nama
#> [1] "Andi"

andi$sapa()
#> [1] "Halo, nama saya Andi"

Gunakan $new() untuk membuat objek. Setelah itu, akses field atau jalankan method melalui $, misalnya andi$nama atau andi$sapa().

4. Menambahkan perilaku yang mengubah data

Method juga dapat memperbarui field milik objek. Berikut contoh sederhana untuk menaikkan umur:

Orang <- R6Class(
  "Orang",
  public = list(
    nama = NULL,
    umur = NULL,

    initialize = function(nama, umur) {
      self$nama <- nama
      self$umur <- umur
    },

    tambah_umur = function(tahun = 1) {
      self$umur <- self$umur + tahun
      invisible(self)
    }
  )
)

budi <- Orang$new("Budi", 30)
budi$tambah_umur(2)
budi$umur
#> [1] 32

invisible(self) membuat method mengembalikan objek tanpa mencetaknya. Ini berguna bila kita ingin memanggil beberapa method secara berantai, meskipun untuk contoh awal hal ini tidak wajib.

5. Membatasi akses dengan private

Tidak semua data perlu bisa diubah langsung dari luar objek. R6 menyediakan bagian private untuk anggota yang hanya digunakan di dalam objek.

Rekening <- R6Class(
  "Rekening",
  public = list(
    initialize = function(saldo_awal = 0) {
      private$.saldo <- saldo_awal
    },

    lihat_saldo = function() {
      private$.saldo
    },

    setor = function(jumlah) {
      if (jumlah <= 0) {
        stop("Jumlah setoran harus lebih besar dari nol.")
      }
      private$.saldo <- private$.saldo + jumlah
      invisible(self)
    }
  ),
  private = list(
    .saldo = NULL
  )
)

rekening <- Rekening$new(100)
rekening$setor(50)
rekening$lihat_saldo()
#> [1] 150

Saldo disimpan sebagai private$.saldo, sehingga pengguna objek tidak mengubahnya secara langsung. Perubahan dilakukan lewat method setor(), tempat kita juga dapat memeriksa bahwa nilai setoran masuk akal. Awalan titik pada .saldo adalah konvensi penamaan, bukan syarat khusus R6.

See also  Positron - Lingkungan Modern untuk Analisis Data Menggunakan R

Kapan R6 berguna?

R6 cocok ketika data dan operasi atas data tersebut perlu disimpan bersama, terutama jika beberapa fungsi harus berbagi dan memperbarui keadaan objek. Contohnya bisa berupa sesi koneksi, keranjang belanja, atau proses yang menyimpan status selama beberapa langkah.

Untuk transformasi data yang sederhana dan tidak perlu menyimpan keadaan, fungsi biasa sering lebih ringkas dan mudah dipahami. R6 juga memakai semantik reference: ketika sebuah objek diberikan ke variabel lain, keduanya dapat menunjuk pada objek yang sama. Karena itu, perubahan melalui satu variabel dapat terlihat melalui variabel lainnya.

objek_a <- Orang$new("Citra", 20)
objek_b <- objek_a
objek_b$umur <- 21
objek_a$umur
#> [1] 21

Perilaku ini berbeda dari banyak objek R biasa yang menggunakan semantik copy-on-modify. Memahami perbedaan tersebut membantu menghindari perubahan data yang tidak disengaja.

Contoh lainnya

Berikut salah satu contoh penggunaan attribute private dan public

library(R6)

BankAccount <- R6Class(
  classname = "BankAccount",
  
  # Bagian Public (dapat diakses dari luar class)
  public = list(
    owner = NULL, # Public field
    
    # Constructor (inisialisasi objek)
    initialize = function(owner, initial_balance = 0) {
      self$owner <- owner
      private$balance <- initial_balance
      cat("Akun berhasil dibuat untuk:", self$owner, "\n")
    },
    
    # Public method untuk menyetor uang
    deposit = function(amount) {
      if (amount > 0) {
        private$balance <- private$balance + amount
        private$log_activity("Deposit")
        cat("Berhasil setor:", amount, "\n")
      } else {
        warning("Jumlah deposit harus lebih dari 0!")
      }
      invisible(self)
    },
    
    # Public method untuk menarik uang
    withdraw = function(amount) {
      if (amount > 0 && amount <= private$balance) {
        private$balance <- private$balance - amount
        private$log_activity("Tarik Tunai")
        cat("Berhasil tarik:", amount, "\n")
      } else {
        warning("Saldo tidak mencukupi atau jumlah tidak valid!")
      }
      invisible(self)
    },
    
    # Public method untuk melihat saldo (mengakses private field)
    get_balance = function() {
      return(private$balance)
    }
  ),
  
  # Bagian Private (hanya dapat diakses dari dalam class/metode)
  private = list(
    balance = 0, # Private field
    
    # Private method (helper internal yang tidak bisa dipanggil dari luar)
    log_activity = function(action) {
      cat("[LOG]", Sys.time(), "-", action, "dilakukan.\n")
    }
  )
)

Kita membuat object instance dari class diatas

# 1. Membuat objek baru (instansiasi)
my_account <- BankAccount$new(owner = "Budi", initial_balance = 1000)

# 2. Mengakses public field
print(my_account$owner) # Output: "Budi"

# 3. Memanggil public method
my_account$deposit(500)
my_account$withdraw(200)

# 4. Mengecek saldo menggunakan public method
my_account$get_balance() # Output: 1300

# 5. Mencoba mengakses private field/method dari luar (Akan menghasilkan error)
# my_account$balance         # Error: object 'balance' not found
# my_account$log_activity()  # Error: attempt to apply non-function

 

See also  Positron - Lingkungan Modern untuk Analisis Data Menggunakan R

 

Penutup

Dengan R6, kita dapat mengelompokkan data, inisialisasi, dan perilaku objek dalam satu tempat. Mulailah dari kelas kecil, tentukan data mana yang perlu dibuka ke pengguna, dan gunakan private ketika perubahan sebaiknya melalui method yang memiliki validasi. R6 bukan pengganti semua fungsi; ia adalah pilihan ketika objek dengan keadaan yang terus berubah membuat kumpulan fungsi mulai sulit dirawat.