7
votes

Comment créer une classe, une sous-classe et des propriétés à Lua?

Je vais avoir du mal à grokking classes dans Lua . Un googling sans fruit m'a conduit aux idées sur les méta-tables et implicite que des bibliothèques tierces sont nécessaires pour simuler / écrire des cours.

Voici un échantillon (juste parce que j'ai remarqué que j'obtiens de meilleures réponses lorsque je fournis un code d'échantillon): p>

--Everything is a table
ElectronicDevice = {};

--Magic happens
mt = {__index=ElectronicDevice};

--This must be a constructor
function ElectronicDeviceFactory ()
    -- Seems that the metatable holds the fields
    return setmetatable ({isOn=true}, mt)
end

-- Simulate properties with get/set functions
function ElectronicDevice:getIsOn()  return self.isOn end
function ElectronicDevice:setIsOn(value)  self.isOn = value end
function ElectronicDevice:Reboot() self.isOn = false;
    self:ResetHardware(); self.isOn = true; end
function ElectronicDevice:ResetHardware()  print('resetting hardware...') end

Router = {};
mt_for_router = {__index=Router}

--Router inherits from ElectronicDevice
Router = setmetatable({},{__index=ElectronicDevice});

--Constructor for subclass, not sure if metatable is supposed to be different
function RouterFactory ()
    return setmetatable ({},mt_for_router)
end

Modem ={};
mt_for_modem = {__index=Modem}

--Modem inherits from ElectronicDevice
Modem = setmetatable({},{__index=ElectronicDevice});

--Constructor for subclass, not sure if metatable is supposed to be different
function ModemFactory ()
    return setmetatable ({},mt_for_modem)
end

function Modem:WarDialNeighborhood(areaCode)
        cisco = RouterFactory();
        --polymorphism
        cisco.Reboot(); --Call reboot on a router
        self.Reboot(); --Call reboot on a modem
        if (self.isOn) then self:StartDialing(areaCode) end;
end

function Modem:StartDialing(areaCode)
    print('now dialing all numbers in ' .. areaCode);
end

testDevice = ElectronicDeviceFactory();
print("The device is on? " .. (testDevice:getIsOn() and "yes" or "no") );
testDevice:Reboot(); --Ok

testRouter = RouterFactory();
testRouter:ResetHardware(); -- nil value

testModem = ModemFactory();
testModem:StartDialing('123'); -- nil value


1 commentaires

Avez-vous lu Ceci ?


7 Réponses :


7
votes

Il y a plusieurs façons de le faire, mais c'est comme ça que je fais (mis à jour avec un tir à l'héritage): xxx

Je ne mettez pas en place de privé, protégé, etc. Bien que ce soit possible .


0 commentaires

1
votes

Il est vraiment facile de faire de l'oop en forme de classe à Lua; Il suffit de mettre toutes les «méthodes» dans le champ index d'une métables: xxx

personnellement, je n'ai jamais eu besoin d'héritage, donc ce qui précède est suffisant pour moi. Si ce n'est pas suffisant, vous pouvez définir une métavère pour la table des méthodes: xxx

mise à jour: Il y a une erreur dans votre code mis à jour: xxx

Notez que vous initialisez routeur et construire mt_for_router de ceci; mais vous réaffectez routeur à une nouvelle table, tandis que mt_for_router pointe toujours sur l'original routeur .

Remplacez le < Code> routeur = {} avec le routeur setmettable ({}, {__ index = electronddevice}) (avant le mt_for_router initialisation).


0 commentaires

3
votes

La façon dont j'ai aimé le faire était en mettant en œuvre une fonction clone ().
Notez que c'est pour Lua 5.0. Je pense que 5,1 a des constructions orientées objet plus intégrées. xxx pré>

vous définissez ensuite une classe comme une table: p> xxx pré>

pour l'instancier ou en dériver, vous utilisez clone () et Vous pouvez remplacer les choses en les transmettant dans une autre table (ou tables) comme mix-ins p> xxx pré>

à appeler, vous utilisez la syntaxe: p> xxx

qui imprimera: p> xxx pré>

Pour dériver une sous-classe, vous définissez essentiellement un autre objet prototype: P>

BigThing = clone(Thing, { 
     -- and override stuff.  
     foo = function(self, x)
         print("hello");
     end
}


0 commentaires

1
votes

Votre code mis à jour est Wordy, mais devrait fonctionner. sauf , vous avez une faute de frappe qui brise l'un des métabiles: xxx

doit lire xxx

le Fragment existant a rendu le modem métables une matrice où le premier élément était presque certainement nul (la valeur habituelle de _g .__ index sauf si vous utilisez strict.lua < / code> ou quelque chose de similaire) et le deuxième élément est électroniquedevice .

Le Lua Wiki Description aura du sens après avoir grokked Metables un peu plus. Une chose qui aide à construire une petite infrastructure permettant de faciliter les modèles habituels.

Je recommanderais également de lire le chapitre sur OOP dans PIL . Vous voudrez également relire les chapitres sur les tables et les métabiles aussi. De plus, j'ai lié à la copie en ligne de la 1ère édition, mais à posséder une copie du 2e est fortement recommandée. Il y a aussi quelques articles dans le Lua Gems livre qui se rapportent. Il est également recommandé.


0 commentaires

10
votes

Voici un exemple de transcription littéral de votre code, avec une bibliothèque code> de classe code> utile qui pourrait être déplacée dans un autre fichier.

Ceci n'est en aucun cas une implémentation canonique de classe code>; N'hésitez pas à définir votre modèle d'objet, mais vous le souhaitez. P>

BaseClass = {}
BaseClass.index = {}
BaseClass.metatable = {__index = BaseClass.index}

DerivedClass = {}
DerivedClass.index = setmetatable({}, {__index = BaseClass.index})
DerivedClass.metatable = {__index = DerivedClass.index}


0 commentaires

4
votes

Si vous ne voulez pas réinventer la roue, une belle bibliothèque Lua met en œuvre plusieurs modèles d'objets. C'est ce qu'on appelle boucle .


0 commentaires

1
votes

Une autre approche simple pour la sous-classe xxx

Vous pouvez toujours utiliser les fonctions de Superclass même si écrasé xxx

n'oubliez pas de Utilisez un point lorsque vous passez à la fonction Superclass


0 commentaires