Menu
Coddy logo textTech

Mixins vs. Vererbung

Teil des Abschnitts Objektorientierte Programmierung der Lua-Journey von Coddy. Lektion 53 von 70.

Du hast zwei Möglichkeiten kennengelernt, Verhalten zu teilen: Vererbung erzeugt über die Prototypkette eine „ist-eine“-Beziehung, während Mixins Funktionen direkt in eine Klasse kopieren. Aber wann solltest du welchen Ansatz verwenden?

Verwende Vererbung, wenn Objekte eine grundlegende Identität teilen. Ein Bird ist ein Animal. Es ist sinnvoll, dass Bird grundlegende Verhaltensweisen von Tieren wie :eat() oder :sleep() erbt. Die Beziehung ist dauerhaft und bestimmt, was das Objekt grundlegend ist.

Verwende mixins, wenn du eine Fähigkeit hinzufügen möchtest, die die Kernidentität des Objekts nicht definiert.

Nicht alle Vögel können fliegen: Pinguine und Strauße sind Vögel, aber sie fliegen nicht. Fliegen ist eine Fähigkeit, kein bestimmendes Merkmal eines Vogels. Ein Flyable-Mixin ermöglicht es dir, Vögeln, die es benötigen, das Fliegen hinzuzufügen, ohne es allen aufzuzwingen.

Die beiden Ansätze funktionieren wunderbar zusammen:

-- Bird erbt von Animal (is-a-Beziehung)
local Bird = {}
Bird.__index = Bird
setmetatable(Bird, {__index = Animal})

-- Flyable ist eine Fähigkeit (Mixin)
local Flyable = {}
function Flyable:fly()
    print(self.name .. " soars through the sky!")
end

-- Wende den Mixin nur auf Vögel an, die fliegen können
applyMixin(Bird, Flyable)

Dieses Muster bietet dir das Beste aus beiden Welten: eine klare Klassenhierarchie für eine gemeinsame Identität sowie flexible Fähigkeiten, die bei Bedarf eingebunden werden können.

challenge icon

Aufgabe

Einfach

Erstellen wir ein kleines Ökosystem von Lebewesen, das zeigt, wann man Vererbung und wann man Mixins verwendet! Du erstellst eine Animal-Basisklasse, einen Bird, der von ihr erbt, und ein Swimmable-Mixin, denn obwohl alle Vögel Tiere sind, können nicht alle Vögel schwimmen.

Du organisierst deinen Code über vier Dateien:

  • Animal.lua: Erstelle die Basisklasse Animal mit einem Konstruktor :new(name), der den Namen speichert. Füge eine :eat()-Methode hinzu, die {name} is eating ausgibt. Dies stellt die gemeinsame grundlegende Identität aller Tiere dar.
  • Swimmable.lua: Erstelle ein Mixin mit einer :swim()-Methode, die {self.name} is swimming ausgibt. Dies ist eine Fähigkeit; nicht alle Lebewesen können schwimmen, daher sollte sie nicht Teil der Vererbungskette sein.
  • Bird.lua: Erstelle eine Bird-Klasse, die von Animal erbt. Der Konstruktor :new(name, canSwim) soll den Konstruktor der übergeordneten Klasse aufrufen und speichern, ob dieser Vogel schwimmen kann. Wende das Swimmable-Mixin auf die Bird-Klasse an. Füge eine :chirp()-Methode hinzu, die {name} chirps! ausgibt. Dies ist ein vogelspezifisches Verhalten.
  • main.lua: Schreibe hier die Hilfsfunktion applyMixin. Lies Eingaben für den Namen eines Vogels und dafür, ob er schwimmen kann (yes oder no). Erstelle eine Bird-Instanz und demonstriere anschließend ihre Fähigkeiten: Rufe :eat() auf (von Animal geerbt), rufe :chirp() auf (eigene Methode von Bird) und rufe :swim() nur auf, wenn der Vogel schwimmen kann.

Du erhältst zwei Eingaben:

  1. Den Namen des Vogels (eine Zeichenkette)
  2. Ob der Vogel schwimmen kann: yes oder no

Wenn der Vogel schwimmen kann, sollte deine Ausgabe so aussehen:

{name} is eating
{name} chirps!
{name} is swimming

Wenn der Vogel nicht schwimmen kann, sollte deine Ausgabe so aussehen:

{name} is eating
{name} chirps!

Wenn die Eingaben beispielsweise Duck und yes lauten, sollte die Ausgabe so aussehen:

Duck is eating
Duck chirps!
Duck is swimming

Wenn die Eingaben Sparrow und no lauten, sollte die Ausgabe so aussehen:

Sparrow is eating
Sparrow chirps!

Diese Aufgabe zeigt den entscheidenden Unterschied: Bird ist ein Animal (Vererbung), aber Schwimmen ist eine optionale Fähigkeit (Mixin). Das Mixin wird auf die Klasse angewendet, aber deine Hauptlogik entscheidet anhand der Fähigkeiten des einzelnen Vogels, ob es verwendet wird!

Probier es selbst

-- main.lua: Einstiegspunkt - erstelle einen Vogel und demonstriere seine Fähigkeiten

-- Hilfsfunktion, um ein Mixin auf eine Klasse anzuwenden
local function applyMixin(class, mixin)
    -- TODO: Kopiere alle Methoden vom Mixin zur Klasse
    
end

-- Wende das Swimmable-Mixin auf Bird an, bevor Bird geladen wird
-- Note: Du musst dies möglicherweise in Bird.lua oder hier behandeln

local Bird = require('Bird')
local Swimmable = require('Swimmable')

-- Wende Mixin auf die Bird-Klasse an
applyMixin(Bird, Swimmable)

-- Eingaben lesen
local name = io.read()
local canSwimInput = io.read()

-- TODO: Bestimme anhand der Eingabe, ob der Vogel schwimmen kann ("yes" oder "no")

-- TODO: Erstelle eine Bird-Instanz mit dem Namen und der Schwimmfähigkeit

-- TODO: Rufe eat() auf - geerbt von Animal

-- TODO: Rufe chirp() auf - eigene Methode von Bird

-- TODO: Rufe swim() nur auf, wenn der Vogel schwimmen kann
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-Lua-Compiler