รูปแบบมิกซิน
ประกอบพฤติกรรมด้วยการคัดลอกเมธอดจากตารางต้นทางหลายตาราง
รูปแบบมิกซิน เป็นบทเรียน Lua Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Lua Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Lua Academy มีบทเรียนทั้งหมด 4 บทเรียน
มิกซ์อินคืออะไร
มิกซ์อินคือตารางของเมธอดที่สามารถคัดลอกไปยังหลายคลาสได้ ต่างจากการสืบทอด มิกซ์อินจะเพิ่มพฤติกรรมโดยไม่สร้างความสัมพันธ์ระหว่างคลาสแม่กับคลาสลูก คลาสหนึ่งสามารถรวมพฤติกรรมจากมิกซ์อินหลายรายการได้
local Flyable={}
function Flyable:fly()
print(self.name.." is flying!")
end
function Flyable:land()
print(self.name.." landed.")
end
local Bird={} Bird.__index=Bird
-- Mix in Flyable
for k,v in pairs(Flyable) do Bird[k]=v end
function Bird.new(name)
return setmetatable({name=name},Bird)
end
Bird.new("Eagle"):fly()มิกซ์อินหลายรายการ
นำมิกซ์อินหลายรายการมาใช้กับคลาสเดียวเพื่อประกอบพฤติกรรมที่ซับซ้อนจากส่วนประกอบง่าย ๆ นี่คือการประกอบแบบแนวนอน โดยมิกซ์อินแต่ละรายการเป็นอิสระต่อกัน
local Serializable={}
function Serializable:toCSV(fields)
local row={}
for _,f in ipairs(fields) do row[#row+1]=tostring(self[f]) end
return table.concat(row,",")
end
local Loggable={}
function Loggable:log(msg)
print("["..os.date("%H:%M").."]["..self.name.."] "..msg)
end
local Entity={} Entity.__index=Entity
for k,v in pairs(Serializable) do Entity[k]=v end
for k,v in pairs(Loggable) do Entity[k]=v end
function Entity.new(n,v) return setmetatable({name=n,value=v},Entity) end
local e=Entity.new("item",42)
e:log("created"); print(e:toCSV({"name","value"}))ความขัดแย้งระหว่างมิกซ์อิน
เมื่อมิกซ์อินสองรายการกำหนดชื่อเมธอดเดียวกัน รายการที่นำมาใช้ทีหลังจะมีผลเหนือกว่า ให้แก้ไขความขัดแย้งอย่างชัดเจนโดยเลือกว่าจะเก็บเวอร์ชันของมิกซ์อินใดไว้ หรือห่อเมธอดทั้งสองเพื่อเรียกใช้ทั้งคู่
local A={speak=function(self) print(self.name.." (A)") end}
local B={speak=function(self) print(self.name.." (B)") end}
local C={} C.__index=C
for k,v in pairs(A) do C[k]=v end
for k,v in pairs(B) do C[k]=v end -- B.speak overwrites A.speak
-- Explicit resolution:
local origA, origB = A.speak, B.speak
function C:speak() origA(self); origB(self) end -- call both
local c=setmetatable({name="X"},C)
c:speak()ตัวช่วย include()
ฟังก์ชันตัวช่วยทำให้การนำมิกซ์อินมาใช้สะดวกขึ้น: include(Class, Mixin) จะคัดลอกเมธอดของมิกซ์อินไปยังคลาส และข้ามฟิลด์ที่มีอยู่แล้ว ดังนั้นเมธอดเดิมจะไม่ถูกเขียนทับ
local function include(cls, mixin)
for k, v in pairs(mixin) do
if cls[k] == nil then
cls[k] = v
end
end
return cls
end
local Comparable={
equals=function(a,b) return a:compareTo(b)==0 end,
lt=function(a,b) return a:compareTo(b)<0 end,
}
local Temp={} Temp.__index=Temp
include(Temp, Comparable)
function Temp.new(c) return setmetatable({c=c},Temp) end
function Temp:compareTo(other) return self.c-other.c end
local a,b=Temp.new(100),Temp.new(50)
print(b.lt and b:lt(a)) -- true (b < a)มิกซ์อินที่มีสถานะ
มิกซ์อินที่ต้องมีสถานะแยกกันในแต่ละอินสแตนซ์จะเริ่มต้นสถานะนั้นในฟังก์ชันเริ่มต้นของมิกซ์อิน ตัวสร้างของคลาสจะเรียกฟังก์ชันเริ่มต้นของมิกซ์อินเพื่อเตรียมสถานะของแต่ละมิกซ์อินในอินสแตนซ์
local Observable={}
function Observable._init(self)
self._listeners={}
end
function Observable:on(event,fn)
self._listeners[event]=self._listeners[event] or {}
self._listeners[event][#self._listeners[event]+1]=fn
end
function Observable:emit(event,...)
for _,fn in ipairs(self._listeners[event] or {}) do fn(...) end
end
local Button={} Button.__index=Button
for k,v in pairs(Observable) do Button[k]=v end
function Button.new(label)
local self=setmetatable({label=label},Button)
Observable._init(self)
return self
end
local btn=Button.new("OK")
btn:on("click",function() print("Clicked!") end)
btn:emit("click")โมดูลมิกซ์อิน
จัดแพ็กเกจพฤติกรรมของมิกซ์อินไว้ในไฟล์โมดูลแยกกัน เรียกใช้โมดูลเหล่านั้นในโมดูลของคลาสแล้วนำมิกซ์อินมาใช้ วิธีนี้ทำให้แต่ละประเด็นด้านพฤติกรรมอยู่ในไฟล์ของตนเอง และช่วยจัดระเบียบฐานโค้ด
-- In a real project:
-- local Loggable = require("mixins.loggable")
-- local Cacheable = require("mixins.cacheable")
-- local MyClass = {}
-- for k,v in pairs(Loggable) do MyClass[k]=v end
-- for k,v in pairs(Cacheable) do MyClass[k]=v end
local TimestampMixin={}
function TimestampMixin:setCreated() self.createdAt=os.time() end
function TimestampMixin:age() return os.time()-self.createdAt end
local Record={} Record.__index=Record
for k,v in pairs(TimestampMixin) do Record[k]=v end
function Record.new(data)
local self=setmetatable(data or {},Record)
self:setCreated()
return self
end
print(Record.new({}).createdAt>0)มิกซ์อินตามบทบาท
กำหนดบทบาทให้วัตถุขณะโปรแกรมทำงาน โดยเลือกใช้ฟังก์ชันมิกซ์อินตามต้องการ วิธีนี้ทำให้กำหนดพฤติกรรมแยกตามอินสแตนซ์ได้ แทนที่จะกำหนดแยกตามคลาส
local Roles={}
Roles.admin={deleteUser=function(self) print(self.name.." deletes user") end}
Roles.editor={editPost=function(self) print(self.name.." edits post") end}
Roles.viewer={viewPost=function(self) print(self.name.." views post") end}
local User={} User.__index=User
function User.new(name,...)
local self=setmetatable({name=name},User)
for _,role in ipairs({...}) do
for k,v in pairs(Roles[role] or {}) do self[k]=v end
end
return self
end
local alice=User.new("Alice","admin","editor")
alice:deleteUser(); alice:editPost()ตรวจสอบการใช้มิกซ์อิน
ติดตามว่ามีการนำมิกซ์อินใดมาใช้กับคลาสแล้วบ้างด้วยเซต วิธีนี้ป้องกันการนำมิกซ์อินเดิมมาใช้ซ้ำ และช่วยให้ตรวจสอบความสามารถของคลาสได้
local function applyMixin(cls, mixin, name)
cls._mixins = cls._mixins or {}
if cls._mixins[name] then return end -- already applied
for k,v in pairs(mixin) do
if k~="_init" then cls[k]=cls[k] or v end
end
cls._mixins[name] = true
end
local Fly={fly=function(self) print(self.name.." flies") end}
local Bird={} Bird.__index=Bird
applyMixin(Bird,Fly,"Fly")
applyMixin(Bird,Fly,"Fly") -- no-op, already applied
print(Bird._mixins.Fly) -- trueมิกซ์อินกับการสืบทอดและการประกอบ
รูปแบบการประกอบสามแบบ ได้แก่ การสืบทอด (เป็นชนิดเดียวกันกับ เป็นลำดับชั้นที่เคร่งครัด) มิกซ์อิน (คัดลอกเมธอด เป็นโครงสร้างแบน) และการประกอบ (มีองค์ประกอบนั้นอยู่ โดยมอบหมายงาน) ให้เลือกตามความสัมพันธ์: animal IS-A creature (การสืบทอด), creature CAN fly (มิกซ์อิน), car HAS engine (การประกอบ)
-- Inheritance: "is-a"
-- local Dog = extends(Animal)
-- Mixin: "can-do"
-- include(Dog, Swimmable)
-- Composition: "has-a"
-- local Dog = {}
-- function Dog.new()
-- return {collar=Collar.new(),chip=Chip.new()}
-- end
print("Pick the right tool for the relationship")แม่แบบมิกซ์อิน
แม่แบบมาตรฐานของมิกซ์อินคือตารางมิกซ์อินที่มีเมธอด มี _init สำหรับสถานะเฉพาะอินสแตนซ์ (ถ้ามี) และมีฟิลด์ชื่อสำหรับตรวจจับความขัดแย้ง การใช้รูปแบบเดียวกันอย่างสม่ำเสมอทำให้มิกซ์อินนำไปประกอบร่วมกันได้ในหลายโครงการ
-- Standard mixin template:
local EventMixin = {}
EventMixin._name = "EventMixin"
function EventMixin._init(self)
self._events = {}
end
function EventMixin:on(e, fn)
self._events[e] = self._events[e] or {}
self._events[e][#self._events[e]+1] = fn
end
function EventMixin:trigger(e, ...)
for _, fn in ipairs(self._events[e] or {}) do fn(...) end
end
-- return EventMixin
print("EventMixin ready for use")คำถามเกี่ยวกับมิกซ์อิน
คุณจะนำมิกซ์อินมาใช้กับคลาสได้อย่างไร
ทบทวน: รูปแบบมิกซ์อิน
มิกซ์อินคัดลอกเมธอดจากตารางต้นทางไปยังคลาสเป้าหมาย เพื่อประกอบพฤติกรรมโดยไม่ใช้การสืบทอด ใช้สำหรับประเด็นที่ตัดขวางหลายส่วน เช่น การแปลงข้อมูลเป็นอนุกรม การบันทึกข้อมูล และการจัดการเหตุการณ์
คำถามที่พบบ่อย
บทเรียน “รูปแบบมิกซิน” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “รูปแบบมิกซิน” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Lua Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Lua Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “รูปแบบมิกซิน”
ประกอบพฤติกรรมด้วยการคัดลอกเมธอดจากตารางต้นทางหลายตาราง คุณปฏิบัติ Lua Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Lua Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Lua Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “รูปแบบมิกซิน” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Lua Academy นี้ได้ไหม
ได้ บทเรียน Lua Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การสืบทอดเดี่ยวด้วยการเชื่อมโยง __index
- การเรียกเมธอดของคลาสแม่ด้วย super
- รูปแบบมิกซิน
- การเขียนทับและพหุรูป