dartoopenkapsulasiMenengah4 mnt baca

Enkapsulasi, Getter & Setter

Menyembunyikan data dengan _private, getter, dan setter.

Menjaga data dari tangan jahil

Sejauh ini field class bisa diubah siapa saja dari mana saja: rekening.saldo = -999999. Di dunia nyata itu bencana. Enkapsulasi adalah prinsip membungkus data agar hanya bisa diakses lewat "pintu resmi" yang terkontrol.

Analogi: brankas bank. Kamu tidak mengambil uang langsung dari tumpukan, tapi lewat teller yang memverifikasi identitas dan mencatat transaksi. Getter/setter adalah teller-nya objek.

Kenapa enkapsulasi ada?

Tiga alasan: validasi (tolak nilai tidak masuk akal), fleksibilitas internal (ubah cara simpan tanpa merusak pemakai), dan read-only (data boleh dibaca tapi tidak ditulis sembarangan).

Private dengan underscore

Di Dart, privasi berbasis file, bukan class: nama diawali _ hanya bisa diakses dari file yang sama.

dart
class Rekening {
  String pemilik;
  double _saldo = 0; // privat: hanya file ini yang bisa sentuh langsung

  Rekening(this.pemilik, this._saldo);

  void setor(double jumlah) {
    if (jumlah > 0) {
      _saldo += jumlah;
      print('Setor $jumlah berhasil.');
    } else {
      print('Jumlah setor harus positif!');
    }
  }

  bool tarik(double jumlah) {
    if (jumlah > 0 && jumlah <= _saldo) {
      _saldo -= jumlah;
      return true;
    }
    print('Penarikan gagal: jumlah tidak valid atau saldo kurang.');
    return false;
  }
}

void main() {
  var r = Rekening('Budi', 100000);
  r.setor(50000);   // OK
  r.setor(-10);     // ditolak dengan pesan
  r.tarik(200000);  // ditolak: saldo kurang
  // r._saldo = 999999; // ERROR jika di file berbeda
}

Method setor/tarik adalah pintu resmi: semua perubahan saldo lewat validasi. Tidak ada jalan pintas mengubah saldo sembarangan.

Getter dan setter: properti terkontrol

Kadang kamu ingin akses terasa seperti field biasa (r.saldo) tapi tetap lewat validasi. Itulah getter dan setter:

dart
class Rekening {
  String pemilik;
  double _saldo;

  Rekening(this.pemilik, this._saldo);

  // Getter: baca saldo seperti properti biasa
  double get saldo => _saldo;

  // Setter: tulis dengan validasi
  set saldo(double nilai) {
    if (nilai < 0) {
      print('Saldo tidak boleh negatif!');
      return;
    }
    _saldo = nilai;
  }

  // Getter komputasi: tanpa field penyimpan
  String get status => _saldo >= 100000 ? 'Sultan' : 'Biasa';
}

void main() {
  var r = Rekening('Budi', 50000);
  print(r.saldo);  // 50000.0, lewat getter
  print(r.status); // Biasa

  r.saldo = 200000; // lewat setter
  print(r.status);  // Sultan

  r.saldo = -50; // ditolak setter
  print(r.saldo); // tetap 200000.0
}

Pemakai menulis r.saldo seperti field biasa, tapi di baliknya ada logika. Getter komputasi (status) bahkan tidak butuh field penyimpan.

Kapan pakai apa?

dart
class Contoh {
  // 1. Field publik: data sederhana tanpa aturan
  String nama = '';

  // 2. Private + getter saja: read-only dari luar
  final String _id;
  Contoh(this._id);
  String get id => _id;

  // 3. Private + getter + setter: butuh validasi
  int _umur = 0;
  int get umur => _umur;
  set umur(int u) {
    if (u >= 0) _umur = u;
  }

  // 4. Method: operasi/aksi, bukan sekadar akses data
  void ulangTahun() => _umur++;
}

Aturan jempol: mulai dari field publik untuk hal sepele, naik ke getter/setter saat butuh validasi atau read-only.

Kesalahan umum

1. Mengira _ privat antar class dalam satu file

dart
// File yang SAMA: _saldo BISA diakses!
void main() {
  var r = Rekening('Budi', 1000);
  // print(r._saldo); // TIDAK ERROR jika main di file yang sama
}

Privasi Dart = level file. Untuk proteksi antar file, pisahkan class ke file sendiri. Di DartPad (satu file), _ tidak memberi proteksi nyata, tapi tetap praktik yang baik.

2. Setter tanpa validasi = field publik yang ribet

dart
// Tidak ada gunanya
// set umur(int u) => _umur = u; // sama saja field publik

Jangan buat getter/setter sekadar gaya. Kalau tidak ada logika tambahan, field publik lebih jujur dan ringkas.

3. Getter dengan efek samping

dart
// SALAH: getter seharusnya tidak mengubah state
// int get hitung {
//   _counter++;
//   return _counter;
// }

Getter dibaca seperti properti, pembaca tidak menyangka ia mengubah data. Efek samping milik method.

Kesimpulan

Enkapsulasi = _ untuk privat + method/getter/setter sebagai pintu resmi. Tujuannya bukan mempersulit, tapi menjamin data selalu valid dan perubahan internal tidak merusak pemakai class.

Catatan teknis: Di Dart 3.x tidak ada kata kunci private/public seperti Java. Konvensinya murni lewat underscore, sederhana tapi efektif untuk privasi level library.

Tantangan

Suhu dengan validasi

Buat class Suhu dengan field privat _celsius, setter yang menolak di bawah -273.15 (nol mutlak), getter celsius, dan getter komputasi fahrenheit (c*9/5+32).

text
// TODO: class Suhu

void main() {
  // TODO: set 25, cetak celsius & fahrenheit. Coba set -300 (harus throw).
}