Artikel ini adalah lanjutan dari artikel Buat program yuk! (http://www.rpgfantasy.web.id/forum/index.php?topic=22.0). Kalau belum pernah membuat program, amat disarankan mengikuti artikel tersebut.
Nah, sudah bisa buat program sendiri? Selamat! Bagaimana, mudah kan? Kali ini kita akan melanjutkan konsep pemrograman yang paling penting, yaitu PBO: Pemrograman Berorientasi Objek. Dalam bahasa Inggris disebut OOP, Object-Oriented Programming. Kenapa ini paling penting? Baca terus untuk mengetahui jawabannya!
Seluruh program yang ditulis di artikel ini akan tetap menggunakan bahasa Ruby, karena kebetulan bahasa ini 100% OOP.
Artikel ini akan aku tulis perlahan sampai artikel Buat program yuk! selesai ditulis.
Nah, setelah lama menunggu artikel Buat Program Yuk! selesai, akhirnya kita bisa melanjutkan mengasah kemampuan pemrograman kita ke tingkat lanjut. Apa itu?
Pemrograman Berbasis Objek (PBO; bahasa Inggrisnya Object-Oriented Programming, atau sering disingkat OOP)
Apa sih PBO itu? Kenapa kita harus belajar PBO? Apa pengetahuan yang kita dapat selama ini tidak mencukupi?
Sebenarnya, dengan berbekal pengetahuan dasar dari artikel Buat program yuk! saja, kita sudah bisa membuat program yang kompleks. Nah, masalah nanti akan muncul saat kita mencoba membuat program yang kompleks. Misalnya, kita kesulitan sendiri merancang bangun program yang enak dibaca dan mudah dimengerti. Lalu, ada beberapa metode yang kita buat yang ternyata punya karakteristik mirip, sehingga seharusnya dapat diringkas. Nah, dengan PBO, beberapa kesulitan ini dapat kita atasi.
Lalu, apa sih objek itu? Kenapa kita perlu menggunakan objek?
Beberapa bagian pada artikel Buat program yuk! (http://forum.rpgfantasy.web.id/index.php?topic=22.0) sebenarnya sudah menggunakan objek, misalnya String, Array, Hash, Numeric, Fixnum, dan banyak lagi. Objek sebenarnya adalah instansi (perwujudan) dari sebuah kelas. Waduh, belum apa-apa sudah ada dua istilah baru???
Tenang, keduanya saling berhubungan, dan sekali mengerti konsepnya, kita tidak akan bingung lagi. Cara termudah memahami istilah kelas dan objek adalah dengan melihat dunia nyata.
Di dunia nyata, kita tentu mengenal objek. Manusia, batu, kucing, air, pohon, dan semua benda adalah objek. Nah, di dunia pemrograman, istilahnya adalah kelas. Jadi, manusia adalah kelas. Kucing adalah kelas. Lalu, objeknya apa? Objeknya adalah perwujudan sebuah kelas. Jadi, objek kelas manusia adalah aku, kalian yang sedang baca artikel ini, Budi, Tono, dan sebagainya. Objek kelas kucing adalah Tom, Kitty, dan sebagainya.
Sebuah kelas pasti memiliki anggota dan karakteristik yang spesifik. Anggota yang dimaksud di sini adalah ciri-ciri yang bisa menunjukkan kelas tersebut. Misalnya, kelas Manusia memiliki dua tangan, dua kaki, satu hidung, satu mulut, dua telinga, dan lain sebagainya. Ciri-ciri ini dinamakan atribut dalam Ruby (istilah lainnya mungkin meliputi data member, property, dsb.). Nah, karakteristiknya, atau lebih spesifik lagi apa yang dapat dilakukan kelas itu, dinamakan metode dalam Ruby (istilah lainnya mungkin meliputi [member] function, dsb.). Contoh, kelas Manusia dapat Makan, Tidur, Menangis, Berbulu, Menikah, dan sebagainya. Yang aku sebutkan barusan adalah metode kelas Manusia.
Nah, dengan dua pengertian tersebut, ayo kita bangun kelas Manusia kita! Kita gunakan kode semu (pseudocode) dulu sebelum melangkah masuk ke format Ruby. Dari ilustrasi di atas, berarti kita dapat menuliskan seperti berikut:
Kelas Manusia
Atribut: mata, hidung, telinga, tangan, kaki
Metode: makan, minum, tidur, menangis, berbulu, menikah
Akhir kelas
Mudah kan? Tapi, seperti apa contoh sebuah metode itu? Metode sendiri sebenarnya sama dengan fungsi yang sudah kita pelajari selama ini. Ambil saja metode makan kita. Apa saja yang perlu Manusia lakukan supaya bisa makan?
Metode makan
Masukkan makanan ke mulut
Kunyah
Telan
Akhir metode
Benarkah sesederhana itu? Memang! Lalu, bagaimana membuat sebuah kelas dan objek di Ruby?
Sebelum kita mulai, perlu diingat bahwa Ruby adalah bahasa pemrograman yang sepenuhnya PBO. Ruby memiliki sebuah kelas utama, yaitu Object. Semua kelas Ruby termasuk dalam kelas Object, bahkan kelas-kelas yang kita buat sendiri. Kita akan bahas sifat-sifat kelas di Ruby setelah kita bisa membuat kelas kita sendiri.
Mudah saja, sebuah kelas di Ruby dibuat dengan blok class (ingat, sebuah blok selalu diawali kata kunci, misalnya if, while, until, unless, dan diakhiri end). Formatnya seperti ini:
class NamaKelas
# daftar atribut dan method
end
Ingat, nama kelas selalu diawali huruf besar. Setelahnya bebas, mengikuti aturan penamaan variabel.
Untuk membuat objeknya, ini yang harus kita lakukan:
nama_objek = NamaKelas.new
Sederhana kan? Lalu, bagaimana cara mengisi kelas kita?
Nah, ayo kita buat atributnya dulu. Secara umum, ada 2 atribut dalam Ruby:
Reader attributeAtribut jenis ini hanya dapat
dibaca, jadi nilainya tidak dapat diubah dari luar kelas (objek). Kenapa begitu? Tentu saja untuk masalah keamanan :) Sebuah reader attribute ditandai dengan kata kunci
attr_reader. Contoh!
class Manusia
attr_reader :mata
attr_reader :hidung
# Kalau daftar reader attribute-nya banyak, bisa diringkas seperti berikut:
attr_reader :tangan, :kaki, :telinga
end
Waduh, kok aneh begitu? Jangan khawatir, ini bukan hal yang baru. Anggap saja atribut adalah variabel milik sebuah kelas tertentu. Pembuatan atribut memang dilakukan dengan format
:nama_atribut. Jangan lupa spasi setelah kata kunci
attr_reader.
Lalu, kenapa sih atribut ini hanya bisa dibaca? Ayo, jalankan irb dan buat kelas Manusia tersebut, lalu jalankan perintah ini:
saya = Manusia.new
saya.tangan = 2 # coba kita ubah nilai atribut tangan...
Apa yang terjadi?
Kutip dari: irbundefined method `tangan=' for #<Manusia:0x2f8b2c0>
Jelas kan?
Membuat reader attribute sebenarnya sama dengan membuat metode berikut:
class Manusia
def mata
return @mata
end
end
Hanya saja, dengan
attr_reader metode tersebut otomatis dibuatkan oleh Ruby. Enak kan?
Jenis atribut berikutnya adalah...
Writer attributeTerbalik dengan attr_reader, atribut ini hanya bisa
ditulisi, dalam pengertian diberi nilai dari luar kelas (objek). Kata kuncinya adalah
attr_writer. Contoh!
class Manusia
attr_writer :rambut
end
Lho, atribut-atribut sebelumnya ke mana? Di sinilah enaknya Ruby. Sebuah kelas dapat ditulis ulang berkali-kali, dan Ruby akan otomatis menambahkan isi-isi yang baru ke kelas sebelumnya. Itulah sebabnya di RGSS orang-orang sering menuliskan kelas-kelas yang sudah ada dengan penambahan atau modifikasi baru di bawah kelas aslinya.
Lalu, kenapa kelas ini hanya bisa ditulisi? Contoh!
saya.rambut = "jabrik" # Ubah nilai atribut ini
Tidak akan terjadi kesalahan. Tapi, kalau kita coba baca atribut
rambut, akan terjadi kesalahan Undefined method "rambut".
Membuat writer attribute sebenarnya sama dengan membuat metode berikut:
class Manusia
def rambut=(rambut)
@rambut = rambut
end
end
Sekali lagi, Ruby mengotomatisasikan pembuatan metode ini dengan
attr_writer.
Lha terus kalau aku ingin atribut yang bisa dibaca dan ditulis, bagaimana dong?
Ada satu lagi tipe atribut spesial yang tidak disebutkan di buku manual, yaitu:
Accessor attribute
Para pembuat skrip RGSS pasti sudah familiar dengan atribut ini. Kata kuncinya adalah attr_accessor. Dengan demikian, atribut kita bisa ditulisi dan dibaca. Contoh!
class Manusia
attr_accessor :jari
end
Coba jalankan perintah ini setelahnya:
saya.jari = 10
saya.jari
Tidak akan terjadi kesalahan.
Membuat sebuah accessor attribute sebenarnya sama dengan membuat dua metode berbeda seperti berikut:
class Manusia
def jari=(jari)
@jari = jari
end
def jari
return @jari
end
end
Berbahagialah karena Ruby otomatis membuatkan keduanya untuk kita dengan attr_accessor :D
Nah, tapi apa itu @jari? Kenapa bentuk itu baru muncul sekarang?
Sebenarnya @jari adalah variabel, namun khusus milik kelas Manusia, atribut :jari (:jari sendiri sebenarnya adalah sebuah objek Symbol, tapi ini tidak usah diambil pusing). Jadi, istilah gampangnya, @jari adalah variabel untuk mengakses atribut jari. Jadi, misalkan saja kita punya atribut :umur dalam tahun. Tiap tahun manusia selalu berulang tahun kan? Nah, metode ulang tahun kita bisa dituliskan seperti ini:
class Manusia
attr_reader :umur
def ulang_tahun
@umur += 1 # ingat, ini sama artinya dengan @umur = @umur + 1
end
end
Atau iseng-iseng kita ingin menghitung umurnya dalam hari?
class Manusia
def umur_dalam_hari
return @umur * 365
end
end
Mudah kan? Membuat metode pun sudah pernah kita pelajari sebelumnya, jadi semestinya tidak ada masalah. Kalau ada yang lupa, coba baca lagi bagian tentang metode (http://forum.rpgfantasy.web.id/index.php?topic=22.msg553#msg553).
Yuk latihan sebentar sebelum kita melanjutkan!
Latihan kita sederhana saja. Buatlah sebuah kelas Mobil dengan karakteristik sebagai berikut:
Ciri-ciri: jenis (sedan, MPV, dll.; caranya bebas), jumlah tempat duduk, jumlah orang yang ada dalam mobil (supir dihitung ya :)), kapasitas bensin maksimal, bensin yang tersedia, gigi persneling (kita anggap otomatis saja, dengan gigi P/Parking, R/Reverse, N/Normal, D/Drive, S/Speeding), jumlah kilometer yang sudah ditempuh.
Buatkan metode-metode berikut:
1) Mengemudi. Berikan parameter jarak tempuh, dalam kilometer. Tergantung gigi persneling saat itu, konsumsi bensin yang diperlukan per kilometernya adalah (dalam liter):
P: 0
R: 0.05
N: 0
D: 0.1
S: 0.3
Kalikan dengan jumlah orang yang ada di dalam mobil saat itu.
Beri tahu jika bensin sudah tinggal 10% dari kapasitas maksimalnya.
2) Ganti gigi. Berikan parameter gigi yang baru.
3) Isi bensin. Berikan parameter jumlah bensin yang diisikan, dalam liter. Jika melebihi kapasitas, berikan pesan.
4) Perawatan. Tiap 1000 kilometer, berikan pesan bahwa mobil perlu perawatan.
Itu saja dulu. Gampang kan? :)
OK? Bagaimana? Susah tidak? Kalau kesulitan, coba tengok jawaban soal latihan berikut ini. Ini hanyalah salah satu jawaban, pekerjaan kalian mungkin berbeda atau bahkan lebih singkat dari jawaban berikut.
class Mobil
attr_reader :tipe, :kursi, :jml_orang, :bensin_max, :bensin_skrg, :gigi, :km
# Gigi yang diizinkan
GIGI = ["P", "R", "N", "D", "S"]
# Konstanta pemakaian bensin berdasarkan gigi
KONSUMSI_BENSIN = {
"P" => 0,
"R" => 0.05,
"N" => 0,
"D" => 0.1,
"S" => 0.3
}
# Inisialisasi
def initialize
@tipe = ""
@kursi = 4
@jml_orang = 1 # diasumsikan selalu ada sopir
@bensin_max = 5
@bensin_skrg = 5
@gigi = "P"
@km = 0
end
# Tambahan metode untuk mencoba nomor 1
def jml_orang=(jml_orang)
@jml_orang = jml_orang
end
# nomor 1
def mengemudi(jarak_tempuh)
# Hitung jumlah bensin yang diperlukan
bensin_perlu = KONSUMSI_BENSIN[@gigi] * @jml_orang * jarak_tempuh
# Bensin cukup?
if bensin_perlu > @bensin_skrg
p "Bensin tidak cukup!"
else
# Tambahkan jumlah km
@km += jarak_tempuh
# Kurangi bensin
@bensin_skrg -= bensin_perlu
# Keluarkan pesan jumlah bensin sekarang
p "Bensin: " + @bensin_skrg.to_s
# Bensin hampir habis?
if @bensin_skrg <= 0.1 * @bensin_max
p "Bensin hampir habis."
end
end
end
# Nomor 2
def ganti_gigi(gigi_baru)
# Gigi diizinkan?
if GIGI.include?(gigi_baru)
@gigi = gigi_baru
p "Gigi diganti ke " + @gigi
else
p "Gigi tidak dikenali."
end
end
# Nomor 3
def isi_bensin(bensin_baru)
@bensin_skrg += bensin_baru
if @bensin_skrg > @bensin_max
p "Bensin berlebih!"
@bensin_skrg = @bensin_max
end
p "Bensin sekarang: " + @bensin_skrg.to_s
end
# Nomor 4
def perawatan
# Perlu perawatan?
if @km >= 1000
p "Perlu perawatan."
# Reset kilometer
@km -= 1000
else
p "Belum perlu perawatan."
end
end
end
Lha terus, bagaimana mengetes bahwa kelas ini sudah sesuai dengan permintaan soal? Ya dicoba saja ;) misalnya seperti ini:
Jumlah orang yang naik mobilku adalah 5 orang. Mulai dengan mengganti gigi ke D (Drive) lalu jalan sejauh 4 km. Karena jalanan agak sepi, ngebut yuk! Ganti gigi ke S (Speed) dan jalan lagi sejauh 4 km. Apa kira-kira bensinnya habis? Diisi saja! Setelah mengisi bensin, sekalian cek apa mobil perlu perawatan.
mobilku = Mobil.new
mobilku.jml_orang = 5
mobilku.ganti_gigi("D")
mobilku.mengemudi(4)
mobilku.ganti_gigi("S")
mobilku.mengemudi(4)
mobilku.isi_bensin(4)
mobilku.perawatan
Jalankan dan lihat hasilnya :)
Nah, sebenarnya materi tentang kelas dan objek selesai sampai di sini. Sisanya, sayangnya, adalah teori :) teori tentang PBO memang agak banyak dibanding prakteknya, karena secara sepintas tidak ada perbedaan antara PBO dengan pemrograman konvensional, hanya saja pada PBO semuanya adalah objek. Tapi jangan khawatir, di tiap teori aku akan selipi contoh nyatanya, supaya teori-teori ini tidak menjadi teori belaka.
Teori-teori berikutnya yang akan dibahas meliputi:
1. Batasan akses
Ada kalanya kita ingin membatasi akses ke kelas kita, misalkan beberapa fungsi tidak diperlukan oleh pengguna namun diperlukan oleh kelas kita. Bagaimana cara membatasinya pada Ruby?
2. Sifat-sifat objek
Kalau berbicara tentang objek, topik ini tidak akan pernah ketinggalan. Objek memiliki beberapa sifat penting, misalnya dapat diturunkan (inheritance), dapat "disembunyikan" (encapsulation), dan memiliki banyak bentuk (polymorphism). Kita akan bahas satu per satu lengkap dengan contohnya dan implementasinya di Ruby.
Wah ternyata untuk mengingat semua teori PBO butuh dua tahun :D nah setelah pikiran segar kembali, kita lanjutkan teori-teori pada PBO.
Selama ini, kita menulis atribut dan metode kelas kita agar dapat diakses oleh pengguna kelas kita. Ada kalanya kita ingin agar beberapa atribut atau metode tidak dapat diakses dari luar kelas, alias hanya milik kelas itu sendiri, atau bisa kita katakan sifatnya
privat. Bisakah kita membuat sesuatu privat?
Jawabnya
bisa. Bagaimana caranya?
Misal kita punya sebuah kelas sederhana bernama
Coba. Kelas ini punya satu metode bernama
Cetak untuk sekedar menulis "Halo!". Satu metode lagi ingin dibuat privat, bernama
Rahasia yang akan mencetak sesuatu yang rahasia, misalkan saja "Rahasia!". Bagaimana implementasinya dalam Ruby?
Mudah saja! Cukup tambahkan kata
private dalam satu baris terpisah sebelum definisi metode yang akan kita privatkan. Lha untuk yang boleh diakses alias
publik? Pada dasarnya, semua atribut dan metode yang kita buat bersifat publik, tapi jika jangkauan akses sempat berubah, berikan kata kunci
public dalam satu baris terpisah sebelum atribut atau metode yang ingin kita buat publik. Bingung? Nii contohnya...
Jika kita mendeklarasikan metode
Cetak duluan:
class Coba
def Cetak
p "Halo!"
end
private
def Rahasia
p "Rahasia!"
end
end
Jika kita mendeklarasikan metode
Rahasia duluan:
class Coba
private
def Rahasia
p "Rahasia!"
end
public # kata kunci ini akan membuat semua yang dituliskan setelahnya memiliki batasan akses publik
def Cetak
p "Halo!"
end
end
Yang manapun kelas yang dibuat, cobalah pakai kelas tersebut, misalkan seperti ini:
tes = Coba.new
tes.Cetak
tes.Rahasia
Saat Ruby menjalankan baris
tes.Rahasia, dia akan mengeluarkan pesan kesalahan seperti ini:
KutipNoMethodError: private method `Cetak' called for #<Coba2:0x6ea558c>
Mudah kan? :) tapi kapan ini digunakan? Pada dasarnya, untuk melindungi data sebuah kelas, sebuah data member biasanya dibuat privat, sementara metode pengaksesnya (baik yang mengambil maupun mengubah nilai; pada beberapa bahasa disebut
property) dibuat publik. Kenapa begitu? Well, ini dibuat agar kita bisa mengontrol penggunaan data member tersebut. Dengan menggunakan metode ini, kita tahu persis siapa yang mengubah nilai suatu data member. Membuat data member publik akan mengurangi kontrol kita terhadap aksesnya, jadi akan lebih sulit untuk menemukan siapa yang mengubah nilainya secara sembarangan, baik disengaja atau tidak.
Untuk data member, Ruby sudah mengotomatisasikan batasan akses dengan atribut (reader, writer, atau accessor), walaupun jika diinginkan kita masih bisa juga membatasi aksesnya, apakah privat atau publik.
Sebenarnya masih ada satu sifat lagi: terlindungi (
protected), tapi kita akan bahas lebih lanjut setelah kita mengenal pewarisan (inheritance).