Inheritance adalah mekanisme yang kuat untuk berbagi implementasi, namun hierarki yang dalam dan kaku membuat kode sulit berubah. Composition over Inheritance adalah prinsip yang merekomendasikan merakit object dari perilaku-perilaku kecil yang dapat dipilih bebas, alih-alih mengunci object ke satu rantai inheritance. Pada chapter ini kita akan membandingkan hierarki inheritance dengan pendekatan composition menggunakan interface di Kotlin. Pembaca akan melihat mengapa composition memudahkan kita merakit hewan seperti kelelawar (terbang dan menyusui) tanpa terjebak oleh keterbatasan single inheritance Kotlin.
Masalah Hierarki Inheritance Mendalam #
Kotlin, seperti Java, tidak mendukung multiple inheritance untuk class. Saat domain tumbuh, hierarki inheritance menjadi kaku karena setiap kombinasi behavior membutuhkan class baru. Bayangkan kita ingin membuat kelelawar: ia terbang dan menyusui. Karena Berburu dan Menyusui berada di cabang berbeda dari Mamalia, kita tidak bisa menyusun keduanya tanpa mengubah struktur class.
open class Hewan { open fun makan() = "makan" }
open class Mamalia : Hewan() { open fun menyusui() = "menyusui" }
open class Karnivora : Mamalia() { open fun berburu() = "berburu" }
class Harimau : Karnivora()
// Bagaimana membuat Kelelawar (terbang + menyusui)? Tidak muat di satu rantai.Hierarki seperti di atas memaksa setiap sub-class mewarisi semua perilaku leluhurnya, termasuk yang tidak relevan. Saat domain bertambah kompleks, hierarki semakin rapuh.
Solusi: Composition dengan Interface #
Composition mengekstrak setiap perilaku menjadi interface kecil yang mandiri. Sebuah object lalu dirakit dengan menyuntikkan kombinasi implementasi yang dibutuhkan. Tidak ada lagi rantai class; setiap behavior adalah komponen yang dapat diganti-bebas.
// Demo Composition over Inheritance.
// === ANTI-POLA: hierarki inheritance dalam ===
open class Hewan {
open fun makan() = "makan"
}
open class Mamalia : Hewan() {
open fun menyusui() = "menyusui"
}
open class Karnivora : Mamalia() {
open fun berburu() = "berburu"
}
class Harimau : Karnivora()
// Masalah: bagaimana membuat "Binatang yang bisa terbang dan menyusui" (Kelelawar)?
// Kotlin tidak mendukung multiple inheritance; hierarki menjadi kaku.
// === SOLUSI: composition ===
interface PerilakuMakan { fun makan(): String }
interface PerilakuBergerak { fun bergerak(): String }
interface PerilakuBerkembangBiak { fun berkembangBiak(): String }
class MakanDaging : PerilakuMakan {
override fun makan() = "makan daging"
}
class MakanTumbuhan : PerilakuMakan {
override fun makan() = "makan tumbuhan"
}
class BergerakTerbang : PerilakuBergerak {
override fun bergerak() = "terbang"
}
class BergerakBerjalan : PerilakuBergerak {
override fun bergerak() = "berjalan"
}
class BerkembangBertelur : PerilakuBerkembangBiak {
override fun berkembangBiak() = "bertelur"
}
class BerkembangMelahirkan : PerilakuBerkembangBiak {
override fun berkembangBiak() = "melahirkan"
}
// Komposisi: hewan dirakit dari perilaku-perilaku
class HewanKomposisi(
private val makan: PerilakuMakan,
private val gerak: PerilakuBergerak,
private val biak: PerilakuBerkembangBiak
) {
fun deskripsi() = "${gerak.bergerak()}, ${makan.makan()}, ${biak.berkembangBiak()}"
}
fun main() {
println("=== Demo Composition over Inheritance ===")
println("--- Inheritance mendalam ---")
val h = Harimau()
println("Harimau: ${h.makan()}, ${h.menyusui()}, ${h.berburu()}")
println()
println("--- Composition fleksibel ---")
val kelelawar = HewanKomposisi(MakanDaging(), BergerakTerbang(), BerkembangMelahirkan())
println("Kelelawar: ${kelelawar.deskripsi()}")
val ayam = HewanKomposisi(MakanTumbuhan(), BergerakBerjalan(), BerkembangBertelur())
println("Ayam: ${ayam.deskripsi()}")
val paus = HewanKomposisi(MakanDaging(), BergerakBerjalan(), BerkembangMelahirkan())
println("Paus: ${paus.deskripsi()}")
val kupu = HewanKomposisi(MakanTumbuhan(), BergerakTerbang(), BerkembangBertelur())
println("Kupu-kupu: ${kupu.deskripsi()}")
}Output yang Dihasilkan:
=== Demo Composition over Inheritance ===
--- Inheritance mendalam ---
Harimau: makan, menyusui, berburu
--- Composition fleksibel ---
Kelelawar: terbang, makan daging, melahirkan
Ayam: berjalan, makan tumbuhan, bertelur
Paus: berjalan, makan daging, melahirkan
Kupu-kupu: terbang, makan tumbuhan, bertelurBedah Kode Baris-per-Baris #
Mari kita amati bagian-bagian penting dari kode di atas:
- Baris 4-13 (hierarki inheritance):
Harimaumewarisi rantaiHewan → Mamalia → Karnivora. Behavior tambahan seperti terbang tidak bisa disisipkan tanpa membuat class perantara baru yang tidak relevan. - Baris 19-21 (interface perilaku): Tiga interface memisahkan konsep makan, bergerak, dan berkembang biak. Masing-masing mandiri dan tidak saling bergantung.
- Baris 23-40 (implementasi konkret): Setiap perilaku punya beberapa implementasi yang bisa dipilih bebas. Menambah
BergerakBerenangcukup membuat satu class baru tanpa menyentuh yang lain. - Baris 43-49 (
HewanKomposisi): Constructor menerima tiga perilaku dan menyimpannya sebagai field. Methoddeskripsihanya mendelegasikan panggilan ke masing-masing komponen. - Baris 55-69 (perakitan): Empat hewan dirakit dengan kombinasi perilaku yang berbeda. Kelelawar dan kupu-kupu sama-sama terbang, namun berbeda pada cara berkembang biak; tidak perlu class perantara baru untuk merepresentasikan hal tersebut.
Inheritance vs Composition #
Berikut perbandingan praktis untuk membantu memilih:
| Aspek | Inheritance | Composition |
|---|---|---|
| Fleksibilitas | Kaku; satu rantai per class | Bebas; kombinasi perilaku apa pun |
| Pengujian | Sulit; mock harus subclass | Mudah; suntik perilaku test |
| Perubahan behavior saat runtime | Tidak bisa | Bisa (ganti field) |
| Boilerplate | Sedikit di awal, mahal saat tumbuh | Sedikit lebih di awal, murah saat tumbuh |
Penutup #
Composition memberi kita kebebasan merakit object dari komponen-komponen kecil yang mandiri. Pendekatan ini cocok ketika domain memiliki banyak kombinasi behavior yang tidak muat di satu rantai inheritance. Pada chapter berikutnya kita akan membahas Immutability: bagaimana menyusun data yang tidak berubah justru membuat kode lebih aman secara concurrent.
Referensi #
Referensi Lanjutan #
- Kotlin documentation home
— halaman utama dokumentasi Kotlin yang merangkum
interface, delegation, danbysebagai pengganti pewarisan