29. Pewarisan lebih dalam — Solusi PR

File .lua solusi: exercises/29/homework/solutions/.

Soal 1 — Vehicle dan Car

Soal. Sebuah Car yang mewarisi describe dari Vehicle.

Solusi.

local Vehicle = {}
Vehicle.__index = Vehicle
function Vehicle.new(name)
    return setmetatable({ name = name }, Vehicle)
end
function Vehicle:describe()
    print(self.name .. " is a vehicle.")
end

local Car = setmetatable({}, { __index = Vehicle })
Car.__index = Car
function Car.new(name)
    return setmetatable(Vehicle.new(name), Car)
end

Car.new("Beetle"):describe()   -- Beetle is a vehicle.  (diwarisi)

Soal 2 — Override

Soal. Car:describe() mengatakan "car" bukan "vehicle".

Solusi. Tambahkan ke class-class di atas:

function Car:describe()
    print(self.name .. " is a car.")
end

Vehicle.new("Cart"):describe()   -- Cart is a vehicle.
Car.new("Beetle"):describe()     -- Beetle is a car.

Sebuah Vehicle menemukan versi aslinya; sebuah Car menemukan miliknya sendiri lebih dulu.

Soal 3 — Memperluas method induk

Soal. Car:describe() menjalankan versi milik induknya, lalu menambahkan satu baris lagi.

Solusi.

function Car:describe()
    Vehicle.describe(self)
    print("  It has four wheels.")
end

Car.new("Beetle"):describe()
-- Beetle is a vehicle.
--   It has four wheels.

Kesalahan umum.

  • Memanggil induk dengan self:describe() di dalam describe akan memanggil method yang sama lagi dan berulang selamanya. Gunakan bentuk titik pada class induk: Vehicle.describe(self).

Tantangan — Dua class turunan

Soal. Bird dan Fish keduanya mewarisi Animal dan meng-override move.

Solusi.

local Animal = {}
Animal.__index = Animal
function Animal.new(name)
    return setmetatable({ name = name }, Animal)
end
function Animal:move()
    print(self.name .. " moves.")
end

local function child()      -- a tiny helper: a class inheriting Animal
    local C = setmetatable({}, { __index = Animal })
    C.__index = C
    function C.new(name) return setmetatable(Animal.new(name), C) end
    return C
end

local Bird = child()
function Bird:move() print(self.name .. " flies.") end

local Fish = child()
function Fish:move() print(self.name .. " swims.") end

local creatures = { Bird.new("Robin"), Fish.new("Nemo") }
for _, c in ipairs(creatures) do
    c:move()
end
-- Robin flies.
-- Nemo swims.

Menempatkan setup pewarisan dari Animal di satu fungsi pembantu membuat kedua class turunan menjadi singkat, dan masing-masing tetap bisa meng-override move dengan caranya sendiri.

Selesai?

Kamu sudah bisa berbagi perilaku dengan sebuah base class dan mengkhususkannya di class turunan — mewarisi, meng-override, dan memperluas. Bab terakhir dari Bagian 6 — Merancang sebuah class yang kecil — membahas cara membuat sebuah class yang nyaman digunakan.