Comment créer une classe, sous-classe et les propriétés en Lua?
Je vais avoir un moment difficile grokking classes dans Lua. Vaines recherches sur google m'a conduit à des idées sur les méta-tables, et implique que les bibliothèques de tiers sont nécessaires pour simuler/classes d'écriture.
Voici un exemple (juste parce que j'ai remarqué-je obtenir les meilleures réponses lorsque j'ai des exemples de code):
public class ElectronicDevice
{
protected bool _isOn;
public bool IsOn { get { return _isOn; } set { _isOn = value; } }
public void Reboot(){_isOn = false; ResetHardware();_isOn = true; }
}
public class Router : ElectronicDevice
{
}
public class Modem :ElectronicDevice
{
public void WarDialNeighborhood(string areaCode)
{
ElectronicDevice cisco = new Router();
cisco.Reboot();
Reboot();
if (_isOn)
StartDialing(areaCode);
}
}
Voici ma première tentative de traduire le ci-dessus en utilisant la technique proposée par Javier.
J'ai pris les conseils de RBerteig. Cependant, les invocations sur les classes dérivées de rendement encore: "attempt to call method 'methodName' (a nil value)"
--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
- Avez-vous lu ceci ?
- Ouais et je l'ai trouvé opaque.
Vous devez vous connecter pour publier un commentaire.
Voici un exemple transcription littérale de votre code, avec un utile
Class
bibliothèque qui peut être déplacé vers un autre fichier.Ce n'est pas une représentation canonique de la mise en œuvre de
Class
; n'hésitez pas à définir votre modèle d'objet comme vous le souhaitez.Si vous étiez à coller aux méthodes get/set pour les propriétés, vous n'auriez pas besoin
__index
et__newindex
fonctions, et pourrait juste avoir un__index
table. Dans ce cas, la façon la plus simple de simuler l'héritage est quelque chose comme ceci:En d'autres termes, la classe dérivée de
__index
table "hérite" de la classe de base__index
table. Cela fonctionne parce que Lua, lors de déléguer à un__index
table, effectivement répète la recherche sur elle, de sorte que le__index
table metamethods sont invoqués.Méfiez-vous également sur l'appel de
obj.Method(...)
vsobj:Method(...)
.obj:Method(...)
est sucre syntaxique pourobj.Method(obj, ...)
, et mélanger les deux appels peuvent produire des erreurs.Il y a un certain nombre de façons dont vous pouvez le faire, mais ce est comment je fais (mis à jour avec un tir à l'héritage):
Je ne suis pas d'œuvre privée, la protection, etc. bien qu'il soit possible.
Si vous ne voulez pas de réinventer la roue, il y a une belle bibliothèque Lua la mise en œuvre de plusieurs modèles d'objet. Il est appelé BOUCLE.
La façon dont j'ai aimé faire, c'est par la mise en œuvre d'un clone() de la fonction.
Notez que c'est pour Lua 5.0. Je pense 5.1 a plus intégrée orientée objet constructions.
Vous pouvez alors définir une classe comme un tableau:
De l'instancier ou à en tirer, vous utilisez clone() et vous pouvez remplacer les choses en les passant dans une autre table (ou tables) comme mix-ins
À appeler, vous utilisez la syntaxe :
À imprimer:
De dériver une sous-classe, vous avez essentiellement de définir un autre prototype de l'objet:
Cette méthode est VRAIMENT simple, peut-être trop simple, mais il a bien fonctionné pour mon projet.
Mise à jour de votre code est verbeux, mais devrait fonctionner. Sauf, vous avez une faute de frappe c'est la rupture de l'un des metatables:
devrait lire
L'existant fragment fait le
Modem
métatable être un tableau dont le premier élément est presque certainement néant (la valeur habituelle de_G.__index
sauf si vous utilisezstrict.lua
ou quelque chose de similaire) et le deuxième élément estElectronicDevice
.La Lua Wiki description du sens, après que vous avez grokked metatables un peu plus. Une chose qui aide est de construire un peu d'infrastructures pour faire les schémas habituels plus facile pour obtenir le droit.
Je recommande aussi la lecture du chapitre sur la programmation orientée objet en PiL. Vous aurez envie de relire les chapitres sur les tables et les metatables trop. Aussi, je suis lié à la copie en ligne de la 1ère édition, mais la possession d'une copie de la 2ème est fortement recommandé. Il y a aussi quelques articles dans la Lua Gemmes livre qui se rapportent. Il est aussi recommandé.
Il est vraiment facile de faire de la classe comme de la programmation orientée objet en Lua; il suffit de mettre tous les "méthodes" dans le
__index
champ d'une métatable:Personnellement, je n'ai jamais eu besoin de l'héritage, de sorte que le ci-dessus est assez pour moi. Si ce n'est pas suffisant, vous pouvez définir une métatable pour les méthodes de table:
mise à jour:
Il y a une erreur dans votre code mis à jour:
Notez que l'initialisation de
Router
, et de construiremt_for_router
à partir de ce; mais alors vous réaffectezRouter
à une nouvelle table, tandis quemt_for_router
encore des points à l'originalRouter
.Remplacer le
Router={}
avec leRouter = setmetatable({},{__index=ElectronicDevice})
(avant lemt_for_router
d'initialisation).Une autre approche simple pour la sous-classe
Vous pouvez toujours utiliser les fonctions de super-classe, même s'il a été écrasé
n'oubliez pas d'utiliser UN point quand il passe de l'auto à la super-classe de la fonction