• Tidak ada hasil yang ditemukan

Multiple Inheritance

BAB 16 OBJECT-ORIENTED PROGRAMMING

16.3 Multiple Inheritance

Sebab objek adalah tidak primitif di Lua, ada beberapa cara untuk melakukan programming berorientasi objek di Lua. Metoda yang kita lihat sebelumnya, menggunakan indeks itu metamethod, apakah mungkin kombinasi kesederhanaan yang terbaik, tampilan, dan fleksibilitas. Meskipun demikian, ada implementasi lain, yang mungkin lebih sesuai pada beberapa kasus tertentu. Di sini kita akan lihat suatu implementasi alternatif yang mengijinkan berbagai warisan di dalam Lua.

Kunci untuk implementasi ini adalah penggunaan dari suatu fungsi untuk metafield __ index. Ingatlah bahwa, ketika suatu tabel metatabel mempunyai suatu fungsi di dalam bidang __ index, Lua akan memanggil fungsi itu kapan saja tidak bisa temukan suatu kunci di dalam tabel yang asli. Kemudian, __ index dapat kunci yang hilang di dalam berapa banyak parent yang diinginkan.

Berbagai warisan berarti bahwa suatu kelas mungkin punya lebih dari satu superclass. Oleh karena itu, kita tidak bisa menggunakan suatu metoda kelas untuk menciptakan subclass-subclass. Sebagai gantinya, kita akan mendefinisikan suatu fungsi spesifik untuk tujuan itu, createClass, yang mempunyai argumentasi superclass dari kelas baru. Fungsi ini menciptakan suatu tabel untuk

menghadirkan kelas yang baru, dan menetapkan metatabelnya dengan suatu __ index

metamethod yang mengerjakan berbagai warisan. Di samping berbagai warisan, masing-masing contoh masih punya satu kelas tunggal, di mana mencari semua metodanya. Oleh karena itu, hubungan antara kelas dan superclass berbeda dari hubungan antara kejadian dan kelas. Yang terutama, suatu kelas tidak bisa menjadi metatabel untuk kejadiannya dan metatabel sendiri pada waktu yang sama. Di dalam implementasi berikut, kita menetapkan suatu kelas sebagai metatabel untuk kejadiannya dan menciptakan tabel yang lain untuk menjadi kelas metatabel itu.

-- look up for `k' in list of tables `plist' local function search (k, plist)

for i=1, table.getn(plist) do

local v = plist[i][k] -- try `i'-th superclass if v then return v end

end end

function createClass (...)

local c = {} -- new class

-- class will search for each method in the list of its -- parents (`arg' is the list of parents)

setmetatable(c, {__index = function (t, k) return search(k, arg)

end})

-- prepare `c' to be the metatable of its instances c.__index = c

-- define a new constructor for this new class function c:new (o)

o = o or {}

setmetatable(o, c) return o

end

-- return new class return c

end

Mari kita mengilustrasikan penggunaan createClass dengan suatu contoh kecil.

Asumsikan kelas Account sebelumnya dan kelas yang lain, Named, hanya dengan dua metoda,

setname dan getname :

Named = {} function Named:getname () return self.name end function Named:setname (n) self.name = n end

Untuk menciptakan suatu kelas baru NamedAccount yang merupakan suatu subclass

keduanya Account dan Named, sederhananya kita panggil createClass :

NamedAccount = createClass(Account, Named)

Untuk menciptakan dan untuk menggunakan contoh, kita lakukan seperti biasanya :

account = NamedAccount:new{name = "Paul"} print(account:getname()) --> Paul

Sekarang mari kita ikuti apa yang terjadi di dalam statemen terakhir. Lua tidak bisa menemukan bidang "getname" di dalam account. Maka, cari bidang __ index dari account

metatabel, dengan nama NamedAccount. Tetapi NamedAccount juga tidak bisa menyediakan

bidang " getname", maka Lua mencari bidang __ index dari NamedAccount metatabel. Sebab bidang ini berisi suatu fungsi, Lua memanggilnya. Fungsi ini kemudian mencari

"getname" pertama ke dalam Account, tidak sukses, dan kemudian ke dalam Named, di mana ditemukan suatu nilai tidak nol, yang merupakan hasil akhir dari pencarian.

Tentu saja, dalam kaitannya dengan dasar kompleksitas dari pencarian ini, tampilan multiple inheritance tidak sama halnya dengan single inheritance. Suatu cara sederhana untuk meningkatkan tampilan ini adalah meng-copy metoda menerima warisan ke dalam subclass. Pada penggunaan teknik ini, index metamethod untuk kelas akan seperti ini :

...

setmetatable(c, {__index = function (t, k) local v = search(k, arg)

t[k] = v -- save for next access return v

end}) ...

Dengan trik ini , akses bagi metoda yang menerima warisan sama cepatnya seperti metoda lokal ( kecuali akses yang pertama). Kelemahannya adalah bahwa sukar untuk mengubah definisi metoda setelah sistem sedang berjalan, sebab perubahan ini tidak menyebarkan ke sepanjang rantai hirarki.

16.4 Privacy

Banyak orang mempertimbangkan kebebasan pribadi menjadi bagian integral dari suatu bahasa berorientasi objek; status dari tiap objek harus menjadi urusan intern sendiri. Dalam beberapa bahasa berorientasi objek, seperti C++ dan Java, anda dapat mengendalikan apakah suatu bidang objek (juga disebut suatu variabel contoh) atau metoda kelihatan di luar objek itu . Bahasa lain, seperti Smalltalk, membuat semua variabel pribadi dan semua metoda publik. Bahasa berorientasi objek yang pertama, Simula, tidak menawarkan segala hal perlindungan.

Desain utama untuk objek di dalam Lua, yang sudah ditunjukkan sebelumnya, tidak menawarkan mekanisme kebebasan pribadi. Yang sebagian, ini adalah suatu konsekuensi dari penggunaan suatu struktur umum (tabel) untuk menghadirkan objek. Tetapi ini juga mencerminkan beberapa keputusan latar belakang desain Lua. Lua tidak diharapkan untuk bangunan program sangat besar, di mana banyak para programmer dilibatkan untuk periode lama. Kebalikannya, Lua mengarahkan dari program kecil ke program medium, pada umumnya bagian dari suatu sistem lebih besar, secara khas dikembangkan oleh satu atau beberapa orang programmer, atau bahkan oleh bukan para programmer. Oleh karena itu, Lua menghindari pemborosan dan pembatasan tiruan yang terlalu banyak. Jika anda tidak ingin mengakses sesuatu di dalam objek, sebaiknya jangan lakukan itu.

Meskipun demikian, tujuan lain dari Lua yang diharapkan yaitu menjadi fleksibel, menawarkan kepada programmer meta-mekanisme sejauh mana dia dapat menandingi banyak mekanisme berbeda. Walaupun desain dasar untuk objek di dalam Lua tidak menawarkan mekanisme kebebasan pribadi, kita dapat menerapkan objek di dalam cara yang berbeda, supaya mempunyai kendali akses. Walaupun implementasi ini tidak sering digunakan, namun mengandung pelajaran untuk memahami tentang hal itu, kebanyakan karena hal itu menyelidiki beberapa sudut yang menarik dari Lua dan karena bisa menjadi solusi yang baik untuk masalah lain.

Ide dasar desain alternatif ini akan menghadirkan masing-masing objek melalui dua tabel: satu untuk statusnya; yang lain untuk operasinya, atau alat penghubungnya (interface). Objek itu sendiri diakses melalui tabel yang kedua, yaitu, melalui operasi yang menyusun alat penghubungnya. Untuk menghindari akses yang tidak sah, tabel yang menghadirkan status dari suatu objek tidak menetap pada suatu bidang tabel lain; sebagai gantinya, hanya menetap di dalam metoda penutup. Sebagai contoh, untuk menghadirkan rekening bank kita dengan desain ini , kita bisa menciptakan objek baru yang menjalankan fungsi pabrik berikut :

function newAccount (initialBalance)

local self = {balance = initialBalance} local withdraw = function (v)

self.balance = self.balance - v end

local deposit = function (v)

self.balance = self.balance + v end

return { withdraw = withdraw, deposit = deposit, getBalance = getBalance } end

Pertama, fungsi menciptakan suatu tabel untuk menyimpan objek internal dan menyimpannya di variabel lokal self. Kemudian, fungsi menciptakan penutup (yaitu, contoh dari fungsi nested) untuk setiap metoda dari objek. Akhirnya, fungsi menciptakan dan mengembalikan objek eksternal, memetakan nama metoda kepada implementasi metoda yang nyata. Titik kunci di sini adalah bahwa metoda itu tidak mendapatkan self sebagai suatu parameter ekstra; sebagai gantinya, mereka mengakses self secara langsung. Karena tidak ada argumentasi ekstra, kita tidak menggunakan tanda sintaks titik dua untuk memanipulasi objek seperti itu . Metoda dipanggil hanya seperti fungsi umum lainnya :

acc1 = newAccount(100.00) acc1.withdraw(40.00)

print(acc1.getBalance()) --> 60

Desain ini memberi kebebasan pribadi penuh ke apapun yang disimpan di tabel self. Setelah

newAccount kembali, tidak ada cara untuk memperoleh akses langsung ke tabel itu. Kita hanya

dapat mengaksesnya melalui fungsi yang diciptakan di dalam newAccount. Walaupun contoh

kita hanya meletakkan satu variabel contoh ke dalam tabel pribadi, kita dapat menyimpan semua bagian pribadi dari objek di dalam tabel itu . Kita juga dapat mendefinisikan metoda pribadi: mereka seperti metoda publik, tetapi kita tidak meletakkannya di dalam alat penghubung. Sebagai contoh, rekening kita boleh memberi suatu kredit ekstra 10% untuk para pemakai dengan saldo di atas suatu batas tertentu, tetapi kita tidak ingin para pemakai mempunyai akses detil dari perhitungan ini. Kita dapat menerapkan ini sebagai berikut :

function newAccount (initialBalance) local self = {

balance = initialBalance, LIM = 10000.00,

}

local extra = function ()

if self.balance > self.LIM then return self.balance*0.10 else

return 0 end

end

local getBalance = function ()

return self.balance + self.extra() end

Sekali lagi, tidak ada cara pemakai manapun untuk mengakses fungsi extra secara langsung.