Salah satu kemampuan atau fitur yang menarik di dalam paradigma pemrograman beriorientasi obyek (PBO) adalah pewarisan (inheritance). Melalui fitur ini, kita dapat membuat class baru yang memiliki karakteristik mirip dengan class yang lainnya. Dikatakan mirip karena class yang baru ini nantinya dapat memiliki atribut dan method yang sama dengan class yang lain. Selain itu, pada class yang baru ini dapat kita tambahkan atribut dan method khusus yang tidak dimiliki oleh class yang lain.
Pada tutorial kali ini, saya akan memberikan sebuah studi kasus yang mengimplementasikan konsep pewarisan ini di dalam Java.
Sebelum studi kasus diberikan, ada baiknya disimak terlebih dahulu lebih detil tentang apa, mengapa, dan bagaimana konsep pewarisan (inheritance) di Java melalui video yang saya buat berikut ini.
Setelah memahami konsep dasar pewarisan (inheritance) di Java, selanjutnya akan diberikan sebuah studi kasus yang merupakan pengembangan dari studi kasus yang ada di video tutorial di atas.
Studi Kasus
Di sebuah perguruan tinggi (PT) X, terdapat 2 jenis pegawai yaitu: Tenaga Pendidik (Dosen), dan Tenaga Kependidikan (Non Dosen).
Secara umum, atribut data yang dimiliki oleh setiap pegawai di perguruan tinggi X tersebut antara lain:
- id pegawai: String
- nama pegawai: String
- golongan: (integer) -> 1, 2
- tanggal lahir: Date
Adapun khusus untuk pegawai dosen, ada tambahan atribut yaitu ‘NIDN’ (Nomor Induk Dosen Nasional) yang sifatnya wajib dimiliki oleh setiap dosen.
Selanjutnya, secara umum semua pegawai yang ada di PT X tersebut akan mendapatkan gaji pokok yang sama perhitungannya, dengan ketentuan:
- Golongan 1 berusia kurang dari 40 tahun: Rp 3.500.000
- Golongan 1 berusia 40 tahun ke atas: Rp 4.500.000
- Golongan 2 berusia kurang dari 40 tahun: Rp 5.000.000
- Golongan 2 berusia 40 tahun ke atas: Rp 6.000.000
Selain gaji pokok, setiap pegawai juga akan mendapatkan tunjangan pegawai yang besarannya dibedakan antara dosen dan nondosen, dengan ketentuan:
- Dosen: Rp 1.500.000
- NonDosen: Rp 1.000.000
Ditambah lagi, khusus untuk dosen terdapat tunjangan fungsional yang besarannya tergantung usianya yaitu:
- Dosen berusia kurang dari 40 tahun: Rp 1.700.000
- Dosen berusia 40 tahun ke atas: Rp 2.000.000
Sehingga berdasarkan beberapa komponen gaji di atas, total gaji yang diterima oleh setiap jenis pegawai adalah:
- Untuk Dosen: Total Gaji = Gaji Pokok + Tunjangan Pegawai + Tunjangan Fungsional
- Untuk NonDosen: Total Gaji = Gaji Pokok + Tunjangan Pegawai
Selanjutnya kita akan membuat program Java untuk menghitung setiap komponen gaji dan gaji total yang diterima setiap pegawai di PT X tersebut.
Perancangan Class
Berdasarkan informasi di atas, kita mencoba mendesain struktur class untuk studi kasus yang diberikan (disajikan dalam bentuk UML Class).
Rancangan class di atas menggambarkan bahwa class Pegawai yang merupakan superclass dari class Dosen, dan class NonDosen. Terdapat beberapa atribut dari Pegawai yang dimiliki juga oleh class Dosen dan NonDosen (perhatikan atribut yang dicetak tebal/bold). Demikian juga untuk methodnya, yaitu hitungUsia()
, hitungGapok()
, dan printPegawai()
.
Method hitungUsia()
akan digunakan untuk menghitung usia pegawai berdasarkan tanggal lahirnya (di sini menggunakan tipe data LocalDate
), yang nantinya usia ini akan digunakan untuk menghitung gaji pokok dan tunjangan fungsional bagi dosen.
Khusus untuk method printPegawai()
di class Pegawai nantinya hanya akan menampilkan semua atribut pegawai dan juga gaji pokoknya saja. Sedangkan printPegawai()
di class Dosen dan NonDosen, ada perbedaan yaitu selain menampilkan semua atribut pegawai juga dan gaji pokok, juga akan menampilkan nilai tunjangan dan total gajinya. Perbedaan proses pada nama method yang sama antara di superclass dan subclass ini dinamakan overriding. Method di dalam subclass yang meng-override method dari superclass ditandai dengan #.
Coding Time…
Saatnya implementasi coding Java untuk setiap classnya berdasarkan rancangan di atas.
Class Pegawai
import java.time.*; public class Pegawai { // atribut String idPegawai; String nama; int gol; LocalDate tglLahir; // constructor Pegawai(String id, String nama, int gol, LocalDate tgllhr){ this.idPegawai = id; this.nama = nama; this.gol = gol; this.tglLahir = tgllhr; } // method menghitung usia pegawai int hitungUsia(){ // mendapatkan tanggal hari ini LocalDate today = LocalDate.now(); // hitung selisih tgl lahir dan tgl hari ini Period selisih = Period.between(this.tglLahir, today); return selisih.getYears(); } // hitung gaji pokok berdasarkan golongan dan usia long hitungGapok(){ long gapok = 0; if (this.gol == 1){ if (this.hitungUsia() < 40){ gapok = 3500000; } else { gapok = 4500000; } } else if (this.gol == 2){ if (this.hitungUsia() < 40){ gapok = 5000000; } else { gapok = 6000000; } } return gapok; } // mencetak data pegawai dan gaji pokoknya void printPegawai(){ System.out.println("ID Pegawai : " + this.idPegawai); System.out.println("Nama Pegawai : " + this.nama); System.out.println("Golongan : " + this.gol); System.out.println("Tgl Lahir : " + this.tglLahir); System.out.println("Gaji Pokok : Rp " + this.hitungGapok()); } }
Manfaat dari penggunaan tipe data LocalDate
untuk mendeklarasikan tanggal lahir pegawai adalah kemudahan dalam mencari selisih tanggal hari ini (current date) dengan tanggal lahirnya. Cukup dengan class Period dan method between()
, maka perhitungan usia pegawai dapat dengan mudah dilakukan. Adapun method getYears()
digunakan untuk mendapatkan selisih dua tanggal dalam satuan tahun. Class LocalDate ini terdapat dalam package Java.time.
Class Dosen
import java.time.*; public class Dosen extends Pegawai { // atribut tambahan untuk dosen String nidn; // constructor Dosen(String id, String nama, int gol, LocalDate tgllhr, String nidn){ super(id, nama, gol, tgllhr); this.nidn = nidn; } // menghitung tunjangan pegawai dosen long hitungTunjPegawai(){ long tunjPegawai = 1500000; return tunjPegawai; } // menghitung tunjangan fungsional dosen long hitungTunjFungsional(){ long tunjFungsional; if (this.hitungUsia() < 40){ tunjFungsional = 1700000; } else { tunjFungsional = 2000000; } return tunjFungsional; } // menghitung total gaji long hitungTotalGaji(){ long total = this.hitungGapok() + this.hitungTunjPegawai() + this.hitungTunjFungsional(); return total; } // cetak data pegawai, rincian gaji, total gaji void printPegawai(){ System.out.println("ID Pegawai : " + this.idPegawai); System.out.println("Nama Pegawai : " + this.nama); System.out.println("Golongan : " + this.gol); System.out.println("Tgl Lahir : " + this.tglLahir); System.out.println("NIDN : " + this.nidn); System.out.println("Usia : " + this.hitungUsia() + " tahun"); System.out.println("Gaji Pokok : Rp " + this.hitungGapok()); System.out.println("Tunj Pegawai : Rp " + this.hitungTunjPegawai()); System.out.println("Tunj Fungsi : Rp " + this.hitungTunjFungsional()); System.out.println("Total Gaji : Rp " + this.hitungTotalGaji()); } }
Dikarenakan Dosen merupakan subclass dari Pegawai, maka cukup dengan menambahkan extends
sehingga atribut dan method yang ada di class Pegawai diwariskan kepada class Dosen. Adapun penambahan atribut pada class Dosen hanya pada nidn saja. Sedangkan untuk method, penambahannya hanya pada hitungTunjPegawai()
, hitungTunjFungsional()
, dan hitungTotalGaji()
.
Selanjutnya perhatikan di class Dosen terdapat constructor. Sesuai teori yang ada di video sebelumnya bahwa apabila superclassnya memiliki constructor, maka subclassnya juga memiliki minimal sebuah constructor juga yang diarahkan ke superclassnya menggunakan perintah super()
. Pada constructor Dosen ini terdapat 5 argumen, 4 diantaranya digunakan untuk diarahkan ke constructor superclass, sedangkan yang satu (nidn) diassign ke dalam atribut nidn
.
Untuk method printPegawai()
di dalam class Dosen meng-override method printPegawai()
yang ada di superclassnya disebabkan perbedaan output yang akan ditampilkan.
Class NonDosen
import java.time.*; public class NonDosen extends Pegawai { // constructor NonDosen(String id, String nama, int gol, LocalDate tgllhr){ super(id, nama, gol, tgllhr); } // menghitung tunjangan pegawai nondosen long hitungTunjPegawai(){ long tunjPegawai = 1000000; return tunjPegawai; } // menghitung total gaji long hitungTotalGaji(){ long total = this.hitungGapok() + this.hitungTunjPegawai(); return total; } // cetak data pegawai, rincian gaji, total gaji void printPegawai(){ System.out.println("ID Pegawai : " + this.idPegawai); System.out.println("Nama Pegawai : " + this.nama); System.out.println("Golongan : " + this.gol); System.out.println("Tgl Lahir : " + this.tglLahir); System.out.println("Usia : " + this.hitungUsia() + " tahun"); System.out.println("Gaji Pokok : Rp " + this.hitungGapok()); System.out.println("Tunj Pegawai : Rp " + this.hitungTunjPegawai()); System.out.println("Total Gaji : Rp " + this.hitungTotalGaji()); } }
Class NonDosen ini juga merupakan subclass dari Pegawai, sehingga class ini juga wajib memiliki constructor yang argumennya diarahkan ke constructor superclassnya. Kebetulan argumen dari constructor class NonDosen sama dengan superclassnya.
Untuk atribut class NonDosen tidak ada tambahan baru, sehingga semua atribut dari class ini merupakan inherit (warisan) dari class Pegawai. Method tambahannya adalah hitungTunjPegawai()
dan hitungTotalGaji()
.
Adapun method printPegawai()
juga meng-override method yang sama pada superclassnya karena diinginkan perbedaan proses tampilan.
Terakhir, kita buat main class nya yang di dalamnya terdapat beberapa instansiasi obyek-obyek dari class yang sudah dibuat.
import java.time.*; public class ProjectSIAKAD { public static void main(String[] args) { // contoh obyek data pegawai Pegawai p1 = new Pegawai("P01", "Rosihan Ari", 2, LocalDate.of(1979, 9, 1)); p1.printPegawai(); // contoh obyek data pegawai dosen Dosen p2 = new Dosen("P02", "Dwi Amalia Fitriani", 1, LocalDate.of(1979, 9, 17), "8888"); p2.printPegawai(); // contoh obyek data pegawai nondosen NonDosen p3 = new NonDosen("P03", "Faza Fauzan K", 1, LocalDate.of(2008, 1, 25)); p3.printPegawai(); } }
Dalam contoh di atas, dibuat 3 buah obyek dari class yang berbeda. Apabila dijalankan maka akan muncul tampilan berikut ini.
ID Pegawai : P01 Nama Pegawai : Rosihan Ari Golongan : 2 Tgl Lahir : 1979-09-01 Usia : 41 tahun Gaji Pokok : Rp 6000000 ID Pegawai : P02 Nama Pegawai : Dwi Amalia Fitriani Golongan : 1 Tgl Lahir : 1979-09-17 NIDN : 8888 Usia : 41 tahun Gaji Pokok : Rp 4500000 Tunj Pegawai : Rp 1500000 Tunj Fungsi : Rp 2000000 Total Gaji : Rp 8000000 ID Pegawai : P03 Nama Pegawai : Faza Fauzan K Golongan : 1 Tgl Lahir : 2008-01-25 Usia : 12 tahun Gaji Pokok : Rp 3500000 Tunj Pegawai : Rp 1000000 Total Gaji : Rp 4500000
Mudah bukan konsep pewarisan/inheritance ini?
Oya dari studi kasus yang diberikan, mungkin untuk class Pegawai ini tidak perlu untuk dibuat obyek nya, dikarenakan status pegawai di sini jelas hanya ada 2 yaitu Dosen dan NonDosen. Sehingga ketika mendefinisikan sebuah obyek ya hanya bisa menggunakan class Dosen dan NonDosen saja. Nah bagaimana caranya supaya class Pegawai ini tidak bisa dibuat obyeknya, dengan kata lain seorang pegawai hanya bisa diinstansiasi dari class Dosen dan NonDosen saja? Ini nanti akan dibahas dalam materi abstraksi.
OK.. demikian tutorial mengenai konsep pewarisan (inheritance), semoga dapat dipahami dengan baik dan ada manfaatnya.