dartoopabstractMenengah4 mnt baca

Abstract Class

Class yang tidak bisa diinstansiasi: kontrak untuk child class.

Kontrak yang wajib dipenuhi

Inheritance mewarisi implementasi. Tapi kadang kamu hanya ingin menetapkan aturan: "setiap hewan WAJIB bisa bersuara, caranya terserah". Abstract class adalah class yang tidak bisa dibuat objeknya, berfungsi sebagai kontrak yang wajib dipenuhi anak-anaknya.

Analogi: abstract class itu seperti formulir kontrak kerja. Formulirnya sendiri tidak bisa "dipekerjakan", tapi setiap karyawan (class konkret) yang menandatanganinya wajib memenuhi klausul-klausulnya.

Kenapa abstract class ada?

Untuk memaksa konsistensi desain. Tanpa kontrak, satu programmer membuat method bunyi(), yang lain suara(), dan kode polimorfisme berantakan. Dengan abstract class, compiler MENJAMIN setiap anak punya method yang sama.

Bentuk dasar

dart
abstract class Hewan {
  String nama;
  Hewan(this.nama);

  void makan() => print('$nama makan.'); // method konkret: boleh ada

  // Method abstrak: tanpa badan, WAJIB di-override anak
  void bersuara();
}

// class HewanLangsung extends Hewan {} // ERROR jika tidak override bersuara()

class Kucing extends Hewan {
  Kucing(String nama) : super(nama);

  @override
  void bersuara() => print('$nama: Meong!');
}

void main() {
  // var h = Hewan('x'); // ERROR: abstract tidak bisa diinstansiasi
  Hewan k = Kucing('Kitty'); // boleh: tipe induk, objek anak
  k.makan();
  k.bersuara();
}

Dua jenis anggota:

  • Method konkret (makan()): punya implementasi, diwarisi apa adanya.
  • Method abstrak (bersuara();): tanpa badan, anak WAJIB mengimplementasikannya atau ikut menjadi abstract.

Contoh kedua, abstract sebagai kerangka algoritma (template method):

dart
abstract class Pembayaran {
  // Kerangka tetap: langkah-langkahnya dikunci
  void proses(double jumlah) {
    validasi(jumlah);
    potongSaldo(jumlah);
    kirimNotifikasi();
  }

  void validasi(double jumlah) {
    if (jumlah <= 0) throw ArgumentError('Jumlah harus positif');
  }

  // Langkah yang disesuaikan tiap metode bayar
  void potongSaldo(double jumlah);
  void kirimNotifikasi();
}

class BayarQRIS extends Pembayaran {
  @override
  void potongSaldo(double jumlah) => print('Potong saldo QRIS: $jumlah');

  @override
  void kirimNotifikasi() => print('Notif: QRIS berhasil');
}

void main() {
  Pembayaran p = BayarQRIS();
  p.proses(50000);
}

Induk mengunci alur, anak mengisi detail. Pola ini menjaga konsistensi proses bisnis.

Abstract vs interface (implements)

Dart tidak punya kata kunci interface terpisah: setiap class BISA menjadi interface lewat implements. Bedanya:

// extends: warisi implementasi makan(), penuhi yang abstrak // implements: TIDAK mewarisi kode, tulis ulang SEMUA (lihat contoh di bawah)

dart
abstract class BisaTerbang {
  void terbang(); // murni kontrak, tanpa implementasi
}

class Burung implements BisaTerbang {
  @override
  void terbang() => print('Mengepakkan sayap');
}

class Pesawat implements BisaTerbang {
  @override
  void terbang() => print('Mesin menyala');
}
  • extends: mewarisi kode + wajib penuhi yang abstrak (hubungan "adalah").
  • implements: TIDAK mewarisi kode sama sekali, wajib tulis ulang SEMUA method (hubungan "bisa").

Kesalahan umum

1. Membuat objek dari abstract class

dart
// SALAH
abstract class Hewan {
  void bersuara();
}

void main() {
  // var h = Hewan(); // ERROR: abstract class tidak bisa diinstansiasi
}

2. Anak tidak mengimplementasikan method abstrak

dart
// SALAH: Kucing tidak override bersuara()
// class Kucing extends Hewan {
//   Kucing(String nama) : super(nama);
// } // ERROR: wajib implementasi atau jadikan abstract
dart
// BENAR
class Kucing extends Hewan {
  Kucing(String nama) : super(nama);
  @override
  void bersuara() => print('Meong');
}

3. implements tapi berharap mewarisi kode

dart
abstract class Hewan {
  void makan() => print('makan');
  void bersuara();
}

// SALAH: implements tidak mewarisi makan()
// class Ikan implements Hewan {
//   @override
//   void bersuara() => print('blub');
// } // ERROR: makan() belum diimplementasikan
dart
// BENAR
class Ikan implements Hewan {
  @override
  void makan() => print('Ikan makan plankton');
  @override
  void bersuara() => print('blub');
}

Kesimpulan

Abstract class = kontrak + boleh ada implementasi bersama. Tidak bisa diinstansiasi, anak wajib memenuhi method abstrak. extends untuk "adalah" dengan warisan kode, implements untuk "bisa" sebagai kontrak murni.

Catatan teknis: Method abstrak juga bisa berupa getter/setter abstrak. Dan class yang memakai implements terhadap class biasa tetap wajib mengimplementasikan SEMUA method publiknya, termasuk yang konkret.

Tantangan

Kontrak kendaraan

Buat abstract class Kendaraan dengan method abstract jalan() dan method konkret klakson(). Buat child Motor dan Mobil yang implement jalan().

text
// TODO

void main() {
  // TODO: buat Motor & Mobil, panggil jalan() dan klakson()
}