Objekt Orientiertes Programmieren in Lua


4. Vererbung

Wichtig für OOP ist die Vererbung. Mit Metatables lässt sich das auch in Lua ermöglichen. Um Beispielsweise die Klasse Programmierer von der Klasse Mensch abzuleiten, kann man folgendermaßen vorgehen:


  1. Mensch = { } function Mensch:Schlafen ( ) print ( “Zzzz” ) end function Mensch:Arbeiten ( ) print ( “Lieber nicht…” ) end function Mensch:New (name ) local obj = setmetatable ( { }, { __index = self } ) obj.name = name return obj end Programmierer = { } setmetatable (Programmierer, { __index = Mensch } ) – Das ist der wichtige Punkt function Programmierer:TrinkKaffee ( ) print ( “Hm… lecker Kaffe!” ) self.kaffee = true end function Programmierer:New ( ) local obj = setmetatable ( { }, { __index = self } ) return obj end Spieler = { } setmetatable (Spieler, { __index = Mensch } ) – Hier auch function Spieler:WoWSpielen ( ) end Klaus = Programmierer:New ( “Klaus” ) Klaus:TrinkKaffe ( ) Klaus:Schlafen ( ) Klaus:Arbeiten ( ) Peter = Spieler:New ( “Peter” ) Peter:Schlafen ( ) Peter:Arbeiten ( ) Peter:WoWSpielen ( )
>

Sowohl Programmierer als auch die neue Klasse Spieler sind von der Klasse Mensch abgeleitet. Damit können sie alles tun, was ein Mensch (im Sinne der Klasse) tun kann.
Funktionieren tut das wieder über eine Metatable mit __index. Diesmal wird die Metatable aber für die Klasse und nicht für das fertige Objekt benutzt, so dass ein misslungener Zugriff auf die Klasse direkt auf die übergeordnete umgeleitet wird.

Mehrfachvererbung ist mit ein wenig trickserei auch möglich:


  1. ElternKlasseA = { } function ElternKlasseA:HalloA ( ) print ( “A” ) end ElternKlasseB = { } function ElternKlasseB:HalloB ( ) print ( “B” ) end KindKlasse = { } do – hier kommt die Vererbung local parents = { } for k, v in pairs (ElternKlasseA ) do parents = v end for k, v in pairs (ElternKlasseB ) do parents = v end setmetatable (KindKlasse, { __index = parents } ) end function KindKlasse:New ( ) return setmetatable ( { }, { __index = self } ) end – alle möglichen Sachen für die Kindklasse objekt = KindKlasse:New ( ) objekt:HalloA ( ) objekt:HalloB ( )

In dem doend Block werden alle Elemente der beiden Elternklassen in einer Table zusammengefasst, sodass über das __index auf beide zugegriffen werden kann. Das ganze in doend zusammenzufassen hat den Vorteil, dass es zu keinem Namenskonflikt mit der Variablen parents kommen kann.


5. Zusätzliches

Jetzt kommen noch drei Sachen, um das ganze etwas zu verbessern.

Als erstes ein schönerer Weg um Objekte zu erstellen:


  1. function Programmierer:New (name ) local obj = setmetatable ( { }, { __index = self } ) obj.name = name return obj end function Programmierer:Hallo ( ) print ( “Hallo, ich bin “ .. self.name ) end setmetatable (Programmierer, { __call = Programmierer.New } ) Klaus = Programmierer ( “Klaus” ) Klaus:Hallo ( )

Durch das __call in der Metatable kann Programmierer wie eine Funktion bentutzt werden; jedes mal wenn es aufgerufen wird, wird Programmierer.New aufgerufen.

Das nächste sind private Daten. Das sind Daten die nur von einem Objekt der Klasse erreichbar sind. Dadurch kann sichergestellt werden, dass diese Daten nicht “von außen” verändert werden, oder Funktionen des Objekts aufgerufen werden, die nur für die interne Nutzung vorgesehen sind.
Das ganze wird über lokale Variablen in einem eigenen Block realisiert:


  1. Programmierer = { } do – alle lokalen Variablen zwischen dem do und dem end sind nur hier verfügbar local privat = { } local function TuWirklichWas (self ) print (self.name .. ” programmiert.” ) end function Programmierer:New (name ) local obj = setmetatable ( { }, { __index = self } ) privat = { } – hier wird ein Platz für die privaten Daten des Objekts angelegt obj.name = name privat.kaffeeGetrunken = false return obj end function Programmierer:TrinkKaffee ( ) local daten = privat daten.kaffeGetrunken = true print ( “Lecker Kaffee!” ) end function Programmierer:TuWas ( ) local daten = privat if daten.kaffeeGetrunken then TuWirklichWas (self ) else print ( “Erstmal Kaffee trinken…” ) end end end

Die privaten Daten eines Objekts werden in einer Table gespeichert. Diese Table steckt wiederum in der Table privat, die nur innerhalb des doend Blocks zugänglich ist. über den Trick, das Objekt als Index in dieser Table zu verwenden, kommt man später sehr leicht wieder an die eigentlichen Daten.
Die privaten Funktionen werden direkt als local function deklariert. Hier ist es wichtig, dass man das eigentliche Objekt an die Funktion übergibt, damit sie was damit machen kann.
Damit ist jetzt sichergestellt, dass der Programmierer auch immer genug Kaffee bekommt, bevor er arbeiten muss.

Zu guter letzt wird die Ausgabe von Objekten verschönert. Wenn man versucht ein Objekt auszugeben bekommt man nur etwas wie table: 0035B7F8 statt einer schönen Ausgabe.
Aber auch da hilft wieder die Metatable:


  1. function Programmierer:ToString ( ) print ( “Programmierer (“..self.name.. “)” ) end function Programmierer:New (name ) local obj = setmetatable ( { }, { __index = self, __tostring = self.ToString } ) obj.name = name return obj end function Programmierer:Hallo ( ) print ( “Hallo, ich bin “ .. self.name ) end setmetatable (Programmierer, { __call = Programmierer.New } ) Klaus = Programmierer ( “Klaus” ) print (Klaus ) – schreibt “Programmierer (Klaus)”

Und schon ist auch die Ausgabe nicht mehr ganz unnütz.


6. Nutzen für Addons

Für kleinere Addons ist OOP selten zu gebrauchen, hier gibt es oft einen einfacheren Weg. Allerdings können größere Addons sehr davon Profitieren Teile des Codes in Klassen zu kapseln, um so später einfachereren Zugriff zu haben. Beispiele wären hier UnitFrame oder ActionBar Addons. Viele neue ActionBar Addons haben zum Beispiel eine Klasse für ihre Buttons, auch wenn die genaue Implementieren meist anders aussieht als in diesen Beispielen.
Addons die OOP einsetzen sind unter Anderem:

  • Bartender4
  • Bongos3
  • ag_UnitFrames
  • Grid
  • FuBar
  • FlexBar2

Die genaue Ausführung ist oft unterschiedlich, es läuft aber immer auf das selbe hinaus.

hier geht es zur ersten Seite

Seiten: 1 2

MoP Vorbestellung
MoP Vorschau
Umfrage

Was haltet ihr von den Cross-Realm-Zonen?

Ergebnis anzeigen »

Loading ... Loading ...
ContentAd
Klassenguides
 
... es in den neuen 5er Instanzen in Catacylsm keinen "lila" Loot mehr geben wird? Auch nicht in der jeweils heroischen Version.
Rectangle
mySigs
mySigs.de
Shakes Fidget
Facebook
Interessantes und Ungewöhnliches rund um World of Warcraft