29. Pewarisan secara mendalam

Bab 27 sudah menyinggung pewarisan: satu class yang dibangun di atas class lain. Inilah cara menghindari penulisan kode yang sama dua kali. Dog dan Cat keduanya adalah Animal — punya nama, punya cara dideskripsikan, yang berbeda hanya suara yang mereka keluarkan. Pewarisan menulis bagian yang sama sekali satu kali.

Class dasar

Mulai dengan class yang umum. Semua yang berlaku untuk seluruh keluarga ditulis di sini:

local Animal = {}
Animal.__index = Animal

function Animal.new(name)
    local self = setmetatable({}, Animal)
    self.name = name
    return self
end

function Animal:describe()
    print(self.name .. " is an animal.")
end

Class anak yang mewarisi

Class anak mengarahkan pencariannya ke class dasar — setup dua baris dari Bab 27:

local Dog = setmetatable({}, { __index = Animal })
Dog.__index = Dog

function Dog.new(name)
    local self = Animal.new(name)     -- build with Animal's fields
    return setmetatable(self, Dog)    -- but tagged as a Dog
end

Dog tidak punya describe sendiri, tapi __index di metatabelnya menunjuk ke Animal, sehingga instance Dog bisa menemukannya di sana:

local rex = Dog.new("Rex")
rex:describe()    -- Rex is an animal.   (inherited from Animal)

Pencariannya berjalan melalui rexDogAnimal, berhenti di tempat pertama yang menemukan describe.

Menambahkan perilaku yang hanya dimiliki anak

Beri class anak method yang tidak dimiliki induknya. Method ini berada di class anak, tidak terlihat oleh induk maupun saudara-saudaranya:

function Dog:fetch()
    print(self.name .. " fetches the ball.")
end

rex:fetch()       -- Rex fetches the ball.

Overriding: mengganti method milik induk

Jika class anak mendefinisikan method dengan nama yang sama dengan milik induknya, versi anak yang ditemukan lebih dulu dan yang berlaku — ini disebut overriding:

function Dog:describe()
    print(self.name .. " is a dog.")
end

rex:describe()    -- Rex is a dog.   (Dog's version, not Animal's)

Sekarang pencarian menemukan describe di Dog dan tidak pernah sampai ke Animal.

Memanggil versi milik induk juga

Kadang kamu ingin memperluas method induk, bukan menggantinya: lakukan apa yang dilakukannya, lalu tambahkan sesuatu. Panggil method induk langsung dengan namanya, dan teruskan self:

function Dog:describe()
    Animal.describe(self)                 -- do the Animal part first
    print("  ...specifically, a dog.")    -- then the Dog part
end

rex:describe()
-- Rex is an animal.
--   ...specifically, a dog.

Bentuk titik Animal.describe(self) meneruskan self secara langsung, menjalankan method milik induk pada instance ini. "Memanggil ke atas ke induk" seperti ini adalah salah satu alat paling berguna dalam pemrograman berorientasi objek.

Buka exercises/29/01-animals.lua. Di sana sudah ada Animal dan Dog. Tambahkan Cat yang mewarisi dari Animal, mengganti describe agar menyebutkan bahwa dia adalah kucing, dan menambahkan method meow. Buat satu kucing dan panggil keduanya.

PR

File PR ada di exercises/29/homework/.

Soal 1 — Vehicle dan Car

Buka exercises/29/homework/01-vehicle.lua. Buat class dasar Vehicle dengan .new(name) dan :describe() yang mencetak <name> is a vehicle.. Kemudian buat Car yang mewarisi darinya. Buat sebuah mobil dan panggil :describe() — harusnya menggunakan method yang diwarisi.

Soal 2 — Override

Buka exercises/29/homework/02-override.lua. Mulai dari class Vehicle/Car, ganti :describe() pada Car agar mencetak <name> is a car.. Pastikan Vehicle masih mengatakan "vehicle" dan Car mengatakan "car".

Soal 3 — Perluas induk

Buka exercises/29/homework/03-extend.lua. Ganti Car:describe() agar pertama-tama memanggil Vehicle.describe(self), lalu mencetak baris tambahan, It has four wheels.. Kedua baris harus muncul.

Tantangan — Dua anak

Buka exercises/29/homework/04-two-children.lua. Buat Animal beserta dua anaknya, Bird dan Fish. Masing-masing mengganti :move() untuk mencetak cara mereka bergerak (flies, swims). Buat satu dari masing-masing, masukkan ke dalam sebuah daftar, dan lakukan perulangan memanggil :move().

Mentok atau sudah selesai? Buka halaman solusi PR.