Enkapsulasi dengan Closure
Sembunyikan keadaan privat menggunakan pola objek berbasis closure.
Enkapsulasi dengan Closure adalah pelajaran Lua Academy gratis di CoddyKit. Ini adalah pelajaran 4 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Lua Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Lua Academy mencakup 4 pelajaran total.
Objek Berbasis Closure
Alternatif OOP berbasis metatabel: gunakan closure untuk menyembunyikan keadaan. Objeknya berupa tabel fungsi; semua fungsi menutup variabel privat. Tidak diperlukan metatabel. Keadaan benar-benar privat dan tidak dapat dijangkau dari luar.
local function makeCounter(start)
local count = start or 0 -- truly private
return {
increment = function() count=count+1 end,
decrement = function() count=count-1 end,
get = function() return count end,
reset = function() count=0 end,
}
end
local c = makeCounter(10)
c.increment(); c.increment()
print(c.get()) -- 12
print(c.count) -- nil (truly private!)Privat vs Publik
Dengan closure, perbedaan antara privat dan publik bersifat mutlak: closure berbagi upvalue (privat), sedangkan kode eksternal hanya melihat tabel yang dikembalikan (publik). Tidak ada cara untuk mengakses variabel privat tanpa melalui API publik.
local function makeAccount(initial)
local balance = initial
local transactions = {}
local function record(type, amount)
transactions[#transactions+1] = {type=type,amount=amount}
end
return {
deposit = function(n) record("D",n); balance=balance+n end,
withdraw = function(n)
if n>balance then error("insufficient funds") end
record("W",n); balance=balance-n
end,
balance = function() return balance end,
history = function() return transactions end,
}
endClosure Bersama
Beberapa fungsi dalam tabel yang sama-sama dikembalikan berbagi upvalue yang sama. Dengan cara inilah keadaan dibagikan di antara metode tanpa mengeksposnya kepada publik. Semua metode melihat variabel privat yang sama.
local function makeQueue()
local items = {} -- shared by all methods
local size = 0
return {
enqueue = function(v) size=size+1; items[size]=v end,
dequeue = function()
if size==0 then return nil end
local head=1
while items[head]==nil do head=head+1 end
local v=items[head]; items[head]=nil; return v
end,
isEmpty = function() return size==0 end,
count = function() return size end,
}
endClosure vs Metatabel
Closure: keadaan benar-benar privat, tanpa biaya tambahan metatabel, setiap instans memiliki salinan fungsi sendiri (lebih banyak memori). Metatabel: metode dibagikan (lebih sedikit memori), dapat diperiksa dengan alat debug, dan mendukung pewarisan. Pilih berdasarkan kebutuhan privasi dan jumlah instans.
-- Closure: per-instance functions (more memory)
local function makePoint(x,y)
return {
x = function() return x end,
y = function() return y end,
distance = function()
return math.sqrt(x*x+y*y)
end
}
end
-- Metatable: shared methods (less memory)
-- local Point = {}; Point.__index = Point
-- function Point.new(x,y) return setmetatable({x=x,y=y},Point) endClosure yang Dapat Diubah
Closure atas variabel yang dapat diubah memungkinkan Anda membuat objek berkeadaan tanpa tabel sama sekali. Satu closure dapat menyimpan keadaan dan menghitung hasil.
local function makeAccumulator()
local sum, count = 0, 0
return {
add = function(n) sum=sum+n; count=count+1 end,
mean = function()
return count>0 and sum/count or 0
end,
total = function() return sum end,
n = function() return count end,
}
end
local acc = makeAccumulator()
for _, v in ipairs({10,20,30,40,50}) do
acc.add(v)
end
print(acc.total(),acc.mean(),acc.n()) -- 150 30.0 5Konstruktor dengan Validasi
Konstruktor berbasis closure melakukan validasi dalam fungsi pabrik, bukan dalam metode. Masukan yang tidak valid menyebabkan pabrik mengembalikan nil atau galat sebelum objek apa pun dibuat.
local function makeRange(lo, hi)
assert(lo<=hi,"lo must be <= hi")
return {
contains = function(v) return v>=lo and v<=hi end,
clamp = function(v) return math.max(lo,math.min(hi,v)) end,
lo = function() return lo end,
hi = function() return hi end,
span = function() return hi-lo end,
}
end
local r = makeRange(0,100)
print(r.contains(50)) -- true
print(r.clamp(150)) -- 100Peristiwa dengan Closure
Pemancar peristiwa yang diimplementasikan dengan closure: daftar penangan bersifat privat; add/remove/emit adalah API publiknya.
local function makeEmitter()
local handlers = {}
return {
on = function(event, fn)
handlers[event] = handlers[event] or {}
handlers[event][#handlers[event]+1] = fn
end,
emit = function(event, ...)
for _, fn in ipairs(handlers[event] or {}) do
fn(...)
end
end,
off = function(event) handlers[event] = {} end,
}
end
local emitter = makeEmitter()
emitter.on("data", function(v) print("Got:", v) end)
emitter.emit("data", 42) -- Got: 42Memoisasi Closure
Pembungkus memoize yang menggunakan closure: tembolok bersifat privat, fungsi yang dibungkus juga privat, dan hanya versi yang telah dimemoisasi yang dikembalikan.
local function memoize(fn)
local cache = {}
return function(...)
local key = table.concat({...}, ",")
if cache[key] == nil then
cache[key] = fn(...)
end
return cache[key]
end
end
local expensiveFib
expensiveFib = memoize(function(n)
if n<=1 then return n end
return expensiveFib(n-1)+expensiveFib(n-2)
end)
for i=0,10 do io.write(expensiveFib(i).." ") end
print()Memperluas Objek Closure
Anda dapat memperluas objek berbasis closure dengan membuat objek baru yang memanggil metode milik objek asli. Ini seperti pembungkusan, bukan pewarisan — objek asli didelegasikan.
local function makeTimedCounter(start)
local base = makeCounter and makeCounter(start) or (function()
local c=start or 0
return {inc=function()c=c+1 end,get=function()return c end}
end)()
local callCount = 0
return {
increment = function()
callCount=callCount+1
base.inc()
end,
get = base.get,
calls = function() return callCount end,
}
endKapan Menggunakan Closure
Gunakan OOP berbasis closure ketika: Anda membutuhkan keadaan yang benar-benar privat dan harus aman, hanya memiliki sedikit instans (memori bukan masalah), atau sedang menulis kode bergaya fungsional. Gunakan metatabel ketika: Anda membutuhkan pewarisan, memiliki banyak instans, atau ingin berintegrasi dengan pustaka OOP.
-- Guideline summary:
-- Closures: true privacy, no metatable, self-contained
-- Metatables: shared methods, inheritance, instanceof checks
-- Rule of thumb:
-- < 100 instances with private state -> closures
-- > 100 instances OR need inheritance -> metatables
print("Both patterns are valid Lua OOP.")Pemeriksaan Cepat
Apa keunggulan utama objek berbasis closure dibandingkan objek berbasis metatabel?
Ringkasan: Closure untuk Enkapsulasi
Ringkasan:
- Pola closure: fungsi pabrik mengembalikan tabel metode; keadaan disimpan dalam upvalue
- Benar-benar privat: tidak ada cara untuk mengakses upvalue dari luar
- Semua metode yang dikembalikan berbagi upvalue privat yang sama
- Kompromi: lebih banyak memori per instans, tetapi privasi lebih baik
- Gunakan untuk kode yang kritis terhadap keamanan atau rancangan bergaya fungsional
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Enkapsulasi dengan Closure” gratis?
Ya — teks lengkap “Enkapsulasi dengan Closure” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Lua Academy, upgrade ke CoddyKit PRO. Kursus Lua Academy mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Enkapsulasi dengan Closure”?
Sembunyikan keadaan privat menggunakan pola objek berbasis closure. Kamu berlatih Lua Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai Lua Academy?
Tidak diperlukan pengalaman sebelumnya. Lua Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 4 dari 4.
Berapa lama pelajaran “Enkapsulasi dengan Closure” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran Lua Academy ini?
Ya. Setiap pelajaran Lua Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Class melalui Metatabel
- Konstruktor dan new()
- Metode Instans dan self
- Enkapsulasi dengan Closure