0Pricing
Lua Academy · Lektion

Mixin-Muster

Setzen Sie Verhalten zusammen, indem Sie Methoden aus mehreren Quelltabellen kopieren

Mixin-Muster ist eine kostenlose Lua Academy-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Lua Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Lua Academy-Kurs umfasst insgesamt 4 Lektionen.

Was ist ein Mixin?

Ein Mixin ist eine Tabelle mit Methoden, die in mehrere Klassen kopiert werden können. Im Gegensatz zur Vererbung fügen Mixins Verhalten hinzu, ohne eine Eltern-Kind-Beziehung herzustellen. Eine Klasse kann Verhalten aus mehreren Mixins kombinieren.

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()

Mehrere Mixins

Wenden Sie mehrere Mixins auf eine Klasse an, um komplexes Verhalten aus einfachen Bausteinen zusammenzusetzen. Dies ist eine horizontale Komposition – jedes Mixin ist unabhängig.

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"}))

Mixin-Konflikte

Wenn zwei Mixins denselben Methodennamen definieren, setzt sich das zuletzt angewendete durch. Lösen Sie Konflikte ausdrücklich, indem Sie entscheiden, welche Version des Mixins beibehalten werden soll, oder kapseln Sie beide Versionen, um sie beide aufzurufen.

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()-Hilfsfunktion

Eine Hilfsfunktion vereinfacht das Anwenden von Mixins: include(Class, Mixin) kopiert die Mixin-Methoden in die Klasse und überspringt Felder, die bereits vorhanden sind (dadurch werden bestehende Methoden nicht überschrieben).

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)

Mixin mit Zustand

Mixins, die einen Zustand pro Instanz benötigen, initialisieren ihn in der init-Funktion des Mixins. Der Klassenkonstruktor ruft die init-Funktionen der Mixins auf, um den Zustand jedes Mixins in der Instanz einzurichten.

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")

Mixin-Module

Packen Sie das Verhalten eines Mixins in separate Moduldateien. Binden Sie diese im Klassenmodul ein und wenden Sie sie an. So bleibt jeder Verhaltensaspekt in einer eigenen Datei, und die Codebasis bleibt übersichtlich.

-- 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)

Rollenbasierte Mixins

Weisen Sie Objekten zur Laufzeit Rollen zu, indem Sie Mixin-Funktionen gezielt anwenden. Dadurch lässt sich das Verhalten pro Instanz statt pro Klasse konfigurieren.

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()

Anwendung von Mixins prüfen

Verfolgen Sie mit einer Menge, welche Mixins auf eine Klasse angewendet wurden. So verhindern Sie eine doppelte Anwendung und können die Fähigkeiten einer Klasse untersuchen.

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

Mixins vs. Vererbung vs. Komposition

Drei Arten der Komposition: Vererbung (ist-ein, strenge Hierarchie), Mixins (Methoden kopieren, flach) und Komposition (hat-ein, Delegation). Wählen Sie je nach Beziehung: Ein Tier IST EIN Lebewesen (Vererbung), ein Lebewesen KANN fliegen (Mixin), ein Auto HAT einen Motor (Komposition).

-- 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")

Mixin-Vorlage

Eine standardisierte Mixin-Vorlage: Die Mixin-Tabelle enthält Methoden, optional ein _init für den Zustand pro Instanz und ein Namensfeld zur Konflikterkennung. Ein einheitliches Muster macht Mixins projektübergreifend kombinierbar.

-- 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")

Mixin-Frage

Wie wenden Sie ein Mixin auf eine Klasse an?

Zusammenfassung: Mixin-Muster

Mixins kopieren Methoden aus einer Quelltabelle in die Zielklasse und setzen so Verhalten ohne Vererbung zusammen. Verwenden Sie sie für querschnittliche Belange wie Serialisierung, Protokollierung und Ereignisverarbeitung.

Häufig gestellte Fragen

Ist die Lektion „Mixin-Muster“ kostenlos?

Ja — der vollständige Text von „Mixin-Muster“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Lua Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Lua Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Mixin-Muster“?

Setzen Sie Verhalten zusammen, indem Sie Methoden aus mehreren Quelltabellen kopieren Du übst Lua Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um Lua Academy zu starten?

Keine Vorkenntnisse erforderlich. Lua Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.

Wie lange dauert die Lektion „Mixin-Muster“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser Lua Academy-Lektion Code schreiben und ausführen?

Ja. Jede Lua Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Einfache Vererbung mit __index-Verkettung
  2. Elternmethoden mit super aufrufen
  3. Mixin-Muster
  4. Überschreiben und Polymorphismus
← Zurück zu Lua Academy