Inheritance menjawab relasi “adalah” (is-a): BukuReferensi adalah Buku. Namun sebagian besar relasi di dunia nyata berbentuk “memiliki” (has-a): perpustakaan memiliki koleksi buku, mobil memiliki mesin, pesanan memiliki daftar barang. Memaksakan relasi has-a lewat inheritance menghasilkan hierarki yang rapuh — mobil yang “mewarisi” mesin akan kesulitan ketika mesin harus bisa diganti tanpa membangun mobil baru. Composition adalah teknik untuk relasi has-a: sebuah object menyimpan object lain sebagai attribute, lalu bekerja sama dengannya. Chapter ini membahasnya lengkap dengan pola pendampingnya: delegation.
Relasi has-a: Mobil dan Mesin #
Bentuk paling sederhana dari composition: class menyimpan object lain di dalam attribute-nya sendiri:
class Mesin:
def __init__(self, tenaga_kuda):
self.tenaga_kuda = tenaga_kuda
def hidupkan(self):
return f"Mesin {self.tenaga_kuda} HP menyala"
class Mobil:
def __init__(self, merek, tenaga_kuda):
self.merek = merek
self.mesin = Mesin(tenaga_kuda)
def start(self):
return f"{self.merek}: {self.mesin.hidupkan()}"
mobil = Mobil("Avanza", 100)
print(mobil.start())Output yang Dihasilkan:
Avanza: Mesin 100 HP menyalaMari kita telaah baris-baris kode di atas:
- Baris 8 (
class Mobil:):Mobiltidak mewarisiMesin. Tidak ada tanda kurung, tidak adasuper()— hubungan keduanya bukan pewarisan. - Baris 11 (
self.mesin = Mesin(tenaga_kuda)): constructorMobilmembangun objectMesindan menyimpannya pada attributemesin. Mobil memiliki satu mesin. - Baris 14 (
return f"{self.merek}: {self.mesin.hidupkan()}"): methodstart()memakai object yang dimilikinya — notasiself.mesin.hidupkan()adalah wujud langsung relasi has-a.
Desain ini menjaga tiap class tetap kecil: Mesin hanya tahu soal mesin, Mobil hanya tahu cara mengoordinasikan komponen-komponennya.
Delegation: Meneruskan Pekerjaan #
Melangkah lebih jauh, Mobil bisa membebankan seluruh pekerjaan kepada komponen — pola ini disebut delegation. Method publik Mobil hanya menjadi pintu yang meneruskan panggilan ke object di dalamnya:
class Mesin:
def __init__(self, tenaga_kuda):
self.tenaga_kuda = tenaga_kuda
def hidupkan(self):
return f"Mesin {self.tenaga_kuda} HP menyala"
def matikan(self):
return "Mesin berhenti"
class Mobil:
def __init__(self, merek, tenaga_kuda):
self.merek = merek
self.mesin = Mesin(tenaga_kuda)
def start(self):
return f"{self.merek}: {self.mesin.hidupkan()}"
def stop(self):
return f"{self.merek}: {self.mesin.matikan()}"
mobil = Mobil("Avanza", 100)
print(mobil.start())
print(mobil.stop())Output yang Dihasilkan:
Avanza: Mesin 100 HP menyala
Avanza: Mesin berhentiPemanggil hanya berurusan dengan mobil.start() dan mobil.stop(); detail “bagaimana mesin menyala” sepenuhnya urusan class Mesin. Jika kelak mesin listrik masuk ke program — dengan method hidupkan() yang berbeda — Mobil tidak perlu ditulis ulang; cukup ganti object yang tersimpan di attribute mesin. Inilah fleksibilitas yang tidak dimiliki inheritance: komponen bisa dipertukarkan tanpa menyentuh hierarki class.
Komposisi di Domain Perpustakaan #
Kembali ke domain utama kita — Perpustakaan dan Buku adalah contoh komposisi yang utuh:
class Buku:
def __init__(self, judul, penulis):
self.judul = judul
self.penulis = penulis
def deskripsi(self):
return f"{self.judul} ({self.penulis})"
class Perpustakaan:
def __init__(self, nama):
self.nama = nama
self.koleksi = []
def tambah_buku(self, buku):
self.koleksi.append(buku)
def daftar_koleksi(self):
return [buku.deskripsi() for buku in self.koleksi]
perpus = Perpustakaan("Perpustakaan Kota")
perpus.tambah_buku(Buku("Laskar Pelangi", "Andrea Hirata"))
perpus.tambah_buku(Buku("Bumi Manusia", "Pramoedya A. Toer"))
print(perpus.nama)
print(perpus.daftar_koleksi())Output yang Dihasilkan:
Perpustakaan Kota
['Laskar Pelangi (Andrea Hirata)', 'Bumi Manusia (Pramoedya A. Toer)']Perpustakaan memiliki list yang berisi object-object Buku, dan setiap Buku tetap utuh dengan method serta attribute-nya sendiri — method daftar_koleksi() cukup memanggil buku.deskripsi() untuk tiap anggota. (Detail kecil: buku bisa ada tanpa perpustakaan mana pun, sehingga sebagian literatur menyebut relasi longgar seperti ini aggregation; prinsip teknisnya sama — object berisi object.)
Kapan Komposisi Lebih Baik daripada Inheritance #
Pertanyaan desain antara keduanya bisa diringkas dalam tabel:
| Pertanyaan | Jawaban | Pilihan yang tepat |
|---|---|---|
| Anak adalah versi khusus dari induk? (is-a) | ya | inheritance |
| Class hanya menyimpan dan memakai object lain? (has-a) | ya | composition |
| Komponen perlu bisa diganti saat program berjalan? | ya | composition |
| Perilaku diambil dari banyak sumber berbeda? | ya | composition / mixin |
Ada satu pola yang menggabungkan keduanya dan sangat umum di ekosistem Python: class kecil yang sengaja hidup sebagai “bumbu” untuk dilewarkan ke class lain. Pola mixin itu — beserta izin Python mewarisi dari lebih dari satu class sekaligus — menjadi pokok bahasan Chapter Multiple Inheritance.