Beete als Objekte
Ein Beet ist ein Datensatz, und zwei Funktionen arbeiten mit ihm: lasseWachsen und beschreibeBeet. Daten und die Funktionen, die mit ihnen arbeiten, gehören zusammen, und dafür gibt es Klassen, wie in der Lektion über Objekte. In diesem Schritt werden die Beete zu Objekten der Klasse Beet. Das Programm tut genau dasselbe wie vorher, und seine Ausgabe ändert sich überhaupt nicht. Nur der Code wird aufgeräumter. Ein Programm umzuschreiben, ohne zu ändern, was es tut, heißt Refactoring, und Programmierer machen das ständig.
Zur Erinnerung, wie eine Klasse funktioniert, mit einem von Emmas Hühnern:
local Huhn = {}
Huhn.__index = Huhn
function Huhn.new(name)
local huhn = {name = name, eier = 0}
return setmetatable(huhn, Huhn)
end
function Huhn:legen(anzahl)
self.eier = self.eier + anzahl
end
function Huhn:__tostring()
return self.name .. " (" .. self.eier .. " Eier)"
end
local goldie = Huhn.new("Goldie")
goldie:legen(2)
goldie:legen(1)
print(goldie)
print("Bestes Huhn: " .. tostring(goldie))Das gibt Folgendes aus:
Goldie (3 Eier)
Bestes Huhn: Goldie (3 Eier)Huhn.new erstellt eine Tabelle mit den Daten des Huhns, gibt ihr die Metatabelle Huhn und gibt sie zurück: setmetatable gibt die Tabelle zurück, die es bekommt. Dank Huhn.__index = Huhn sucht ein Huhn, das ein Feld nicht hat, zum Beispiel legen, es in Huhn. Der Doppelpunkt in goldie:legen(2) übergibt das Huhn selbst als self. Und __tostring legt fest, was print und tostring aus einem Huhn machen (%s in string.format nutzt es auch). .. tut das aber nicht, "Bestes Huhn: " .. goldie würde also mit einem Fehler enden. Deshalb ruft das Beispiel tostring(goldie) auf.
Dasselbe gilt für table.concat. Wenn du die Beete selbst statt ihrer Texte zur Liste des Tages hinzufügst, bricht das Programm ab:
main.lua:108: invalid value (table) at index 1 in table for 'concat'Füge also tostring(beet) zur Liste hinzu. Ein weiterer Fehler ist ein Punkt statt des Doppelpunkts. beet.wachsen(wachstum[heute]) übergibt die Anzahl der Tage als self, und die Methode kann kein Feld einer Zahl lesen:
main.lua:44: attempt to index a number value (local 'self')Die Ernte im Hauptprogramm kann bleiben, wie sie ist. Ein Objekt ist weiterhin eine Tabelle, also funktionieren beet.gewachsen und beet.pflanze wie zuvor.
So schreibst du es:
Anweisungen
- 1
Erstelle unter
findePflanzedie KlasseBeet:local Beet = {}undBeet.__index = Beet. Schreibe dannBeet.new(pflanze, samen), das die Tabelle{pflanze = pflanze, samen = samen, gewachsen = 0}erstellt, ihr mitsetmetatabledie MetatabelleBeetgibt und sie zurückgibt. - 2
Mache aus den beiden Funktionen Methoden.
Beet:wachsen(menge)tut, waslasseWachsentut, mitselfstattbeet, undBeet:__tostring()gibt denselben Text zurück wiebeschreibeBeet. - 3
Benutze die Klasse im Hauptprogramm: Lege die Beete mit
Beet.new(pflanze, eintrag.samen)an, lasse sie mitbeet:wachsen(wachstum[heute])wachsen und fügetostring(beet)zur Liste des Tages hinzu. Lösche dann die FunktionenlasseWachsenundbeschreibeBeet, weil sie niemand mehr braucht. (Bliebe irgendwo ein Aufruf einer von ihnen stehen, bräche das Programm mitattempt to call a nil value (global 'lasseWachsen')ab.) Die Ausgabe bleibt genau dieselbe wie im vorigen Schritt:PREISLISTE Karotte: Samen 2, Verkauf 5 Kürbis: Samen 5, Verkauf 20 Erdbeere: Samen 4, Verkauf 12 Weizen: Samen 1, Verkauf 3 Beet 1: Karotte x4 für 8 Münzen Beet 2: Weizen x6 für 6 Münzen Beet 3: Kürbis x2 für 10 Münzen Nicht genug Münzen für Erdbeere x2 Münzen: 6 Tag 1 (sonnig): Karotte 1/3, Weizen 1/2, Kürbis 1/6 Tag 2 (sonnig): Karotte 2/3, Weizen 2/2, Kürbis 2/6 Tag 3 (regnerisch): Karotte 3/3, Weizen 2/2, Kürbis 4/6 Tag 4 (wolkig): Karotte 1/3, Weizen 1/2, Kürbis 5/6 Tag 5 (sonnig): Karotte 2/3, Weizen 2/2, Kürbis 6/6 Tag 6 (wolkig): Karotte 3/3, Weizen 1/2, Kürbis 1/6 Markt: Karotte 8 x 5, Kürbis 2 x 20, Weizen 18 x 3 = 134 Saisonende: 140 Münzen