Kita telah menempuh seluruh pilar OOP satu per satu. Bab ini merangkumnya dalam satu peta, lalu menyatukan pilar-pilar tersebut dalam satu contoh terpadu. Setelah bab ini, pembelajaran berpindah dari cara membangun class ke cara menjaga desain tetap rapi.
Empat Pilar OOP #
| Pilar | Inti Prinsip | Contoh pada Section Ini |
|---|---|---|
| Encapsulation | Sembunyikan data, buka akses terkontrol | RekeningBank dengan field saldo privat |
| Inheritance | Wariskan member ke class turunan | Pegawai menjadi dasar Manajer |
| Polymorphism | Satu panggilan, banyak perilaku | List<Hewan> berisi Kucing dan Sapi |
| Abstraction | Tampilkan kontrak, sembunyikan detail | BangunDatar dengan HitungLuas() abstract |
Abstraction perlu dibedakan dari encapsulation. Encapsulation menyembunyikan data di dalam satu class, sedangkan abstraction menyembunyikan detail kerja di balik kontrak, sehingga pemanggil cukup tahu “apa” tanpa perlu tahu “bagaimana”.
Keempat pilar jarang dipakai sendiri-sendiri. Contoh pada bagian berikutnya memakai semuanya sekaligus dalam satu program penggajian sederhana.
Contoh Terpadu: Penggajian #
public abstract class Karyawan
{
public string Nama { get; }
public int GajiDasar { get; }
protected Karyawan(string nama, int gajiDasar)
{
Nama = nama;
GajiDasar = gajiDasar;
}
public abstract int HitungGaji();
public void TampilkanSlip()
{
Console.WriteLine($"{Nama} menerima gaji Rp{HitungGaji()}.");
}
}
public class KaryawanTetap : Karyawan
{
private int tunjangan;
public KaryawanTetap(string nama, int gajiDasar, int tunjangan) : base(nama, gajiDasar)
{
this.tunjangan = tunjangan;
}
public override int HitungGaji()
{
return GajiDasar + tunjangan;
}
}
public class KaryawanParuhWaktu : Karyawan
{
private int jamKerja;
public KaryawanParuhWaktu(string nama, int gajiPerJam, int jamKerja) : base(nama, gajiPerJam)
{
this.jamKerja = jamKerja;
}
public override int HitungGaji()
{
return GajiDasar * jamKerja;
}
}
List<Karyawan> daftarKaryawan = new List<Karyawan>
{
new KaryawanTetap("Budi", 6000000, 1500000),
new KaryawanParuhWaktu("Siti", 50000, 80)
};
foreach (Karyawan karyawan in daftarKaryawan)
{
karyawan.TampilkanSlip();
}Output yang Dihasilkan:
Budi menerima gaji Rp7500000.
Siti menerima gaji Rp4000000.Mari kita amati peran setiap pilar pada contoh di atas:
- Encapsulation:
tunjangandanjamKerjabersifatprivate; data gaji hanya berubah lewat constructor dan method milik class sendiri. - Abstraction: Class dasar
Karyawanmenyatakan kontrakHitungGaji()tanpa badan;TampilkanSlip()cukup memanggil kontrak tersebut. - Inheritance:
KaryawanTetapdanKaryawanParuhWaktumewarisiNama,GajiDasar, danTampilkanSlip()dariKaryawan. - Polymorphism: Loop mencetak dua format gaji berbeda dari baris kode yang sama, karena dynamic dispatch menjalankan
HitungGaji()milik tiap object.
Sentuhan Single Responsibility Principle #
Satu prinsip desain layak disinggung sejak sekarang: Single Responsibility Principle (SRP). Prinsip ini menyatakan satu class sebaiknya punya satu alasan untuk berubah. Class KaryawanTetap hanya mengurus aturan gaji tetap; bila format slip berubah, yang diedit adalah method TampilkanSlip(), bukan rumus gaji. Ciri class yang mengikuti SRP mudah dikenali: deskripsi tugasnya selesai dalam satu kalimat tanpa kata “dan”.
Empat pilar plus SRP adalah alat bantu, bukan tujuan akhir. Mulailah selalu dari masalah yang ingin diselesaikan, lalu pilih pilar yang paling menjawab masalah tersebut.