Menguasai Pemrograman Berorientasi Objek (OOP) dengan Dart

Class (Cetakan) Blueprint Instantiates Object (Instance) Data Nyata
Ilustrasi hubungan antara Class dan Object.

Pengantar OOP di Dart

Dart, bahasa pemrograman yang menjadi tulang punggung Flutter, dibangun di atas fondasi kuat Pemrograman Berorientasi Objek (OOP). Memahami OOP di Dart bukan hanya soal sintaks, tetapi juga tentang bagaimana kita menstrukturkan kode menjadi lebih modular, dapat dipelihara (maintainable), dan mudah diskalakan. OOP memungkinkan pengembang memodelkan entitas dunia nyata ke dalam kode melalui konsep Class dan Object.

Dalam konteks Dart, segalanya adalah objek, termasuk angka dan fungsi. Namun, prinsip inti OOP—Enkapsulasi, Abstraksi, Pewarisan (Inheritance), dan Polimorfisme—adalah kunci untuk membangun aplikasi yang kompleks dengan elegan. Menguasai empat pilar ini akan sangat meningkatkan kualitas kode Flutter Anda.

1. Class dan Object: Cetakan dan Wujud Nyata

Class adalah cetak biru (blueprint) yang mendefinisikan properti (variabel) dan perilaku (metode/fungsi) dari suatu tipe objek. Sedangkan Object adalah instansiasi nyata dari class tersebut yang menempati memori.

Contoh Deklarasi Class di Dart:


class Mobil {
  // Properti (State)
  String merek;
  int tahunProduksi;

  // Constructor
  Mobil(this.merek, this.tahunProduksi);

  // Metode (Behavior)
  void nyalakanMesin() {
    print('$merek tahun $tahunProduksi siap dijalankan!');
  }
}

void main() {
  // Membuat Object (Instansiasi)
  var mobilSaya = Mobil('Toyota', 2020);
  mobilSaya.nyalakanMesin(); // Output: Toyota tahun 2020 siap dijalankan!
}
            

Penggunaan this.merek dalam constructor adalah sintaks ringkas Dart untuk menginisialisasi properti instance.

2. Enkapsulasi: Melindungi Data

Enkapsulasi adalah praktik membungkus data (properti) dan metode yang beroperasi pada data tersebut dalam satu unit (Class), serta membatasi akses langsung ke beberapa komponen internal. Di Dart, kita menggunakan underscore (_) di awal nama variabel atau fungsi untuk menjadikannya pribadi (private).

Penerapan Enkapsulasi:


class RekeningBank {
  double _saldo = 0.0; // Private

  // Getter untuk membaca saldo secara aman
  double get saldo => _saldo;

  // Setter untuk memodifikasi saldo dengan validasi
  set setor(double jumlah) {
    if (jumlah > 0) {
      _saldo += jumlah;
    }
  }
}

void main() {
  var rekening = RekeningBank();
  rekening.setor = 500.0; // Memanggil setter
  print('Saldo Anda: ${rekening.saldo}'); // Memanggil getter

  // rekening._saldo = -1000; // Ini akan menghasilkan error kompilasi (jika di file yang berbeda)
}
            

Dengan enkapsulasi, kita memaksa pengguna kelas untuk berinteraksi melalui metode publik (getter/setter) yang memungkinkan kontrol atau validasi data.

3. Pewarisan (Inheritance): Memanfaatkan Kode

Pewarisan memungkinkan sebuah class (subclass) mewarisi properti dan metode dari class lain (superclass). Di Dart, ini dilakukan menggunakan kata kunci extends. Ini sangat penting untuk membangun hierarki UI di Flutter (misalnya, StatelessWidget mewarisi dari Widget).


class Hewan {
  void bernafas() {
    print('Hewan sedang bernafas.');
  }
}

class Anjing extends Hewan {
  void gonggong() {
    print('Guk Guk!');
  }

  @override
  void bernafas() {
    // Override metode superclass
    print('Anjing bernafas dengan hidung.');
  }
}

void main() {
  var buddy = Anjing();
  buddy.bernafas(); // Menggunakan metode yang di-override
  buddy.gonggong();
}
            

4. Polimorfisme: Banyak Bentuk

Polimorfisme (banyak bentuk) memungkinkan objek dari class berbeda merespons panggilan metode yang sama dengan cara yang berbeda. Ini sangat erat kaitannya dengan pewarisan dan overriding.

Konsep ini diimplementasikan di Dart melalui Method Overriding (seperti yang dilihat pada contoh bernafas() di atas) dan juga melalui Interface/Abstract Class.


abstract class Bentuk {
  void hitungLuas(); // Metode abstrak, harus diimplementasikan
}

class Persegi extends Bentuk {
  final double sisi;
  Persegi(this.sisi);

  @override
  void hitungLuas() {
    print('Luas Persegi: ${sisi * sisi}');
  }
}

void main() {
  List koleksiBentuk = [Persegi(5.0)];

  for (var bentuk in koleksiBentuk) {
    bentuk.hitungLuas(); // Setiap objek akan menjalankan implementasi hitungLuas-nya sendiri.
  }
}
            

Penggunaan abstract class memaksa semua subclass untuk menyediakan implementasi untuk metode-metode yang dideklarasikan di dalamnya, menjamin konsistensi perilaku.

Kesimpulan

Menguasai OOP dalam Dart adalah prasyarat utama untuk pengembangan aplikasi yang serius, terutama dengan Flutter. Dengan memahami cara Dart menangani Class, Enkapsulasi (menggunakan underscore), Inheritance, dan Polimorfisme, Anda dapat membangun arsitektur aplikasi yang bersih, terstruktur, dan mudah diperluas. Latihan terus-menerus dengan konsep-konsep ini akan memperkuat pemahaman Anda.