0Pricing
Lua Academy · Leçon

Constructeurs et new()

Écrivez des fonctions constructrices qui créent et initialisent des instances.

Constructeurs et new() est une leçon Lua Academy gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Lua Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Lua Academy comprend 4 leçons au total.

Responsabilité du constructeur

Un constructeur crée et initialise une instance. Il reçoit les valeurs initiales, les valide, définit les valeurs par défaut des champs manquants et renvoie la nouvelle instance. Un constructeur bien conçu garantit que chaque instance commence dans un état valide.

local Player = {}
Player.__index = Player

function Player.new(name, hp, mp)
  assert(type(name)=="string" and name~="","need name")
  return setmetatable({
    name = name,
    hp   = hp or 100,
    mp   = mp or 50,
    alive = true,
    items = {},
  }, Player)
end

local p = Player.new("Hero")
print(p.name, p.hp, p.mp)  -- Hero  100  50

Constructeur fluide

Un constructeur fluide renvoie self depuis les méthodes de définition, ce qui permet d'enchaîner les méthodes lors de la construction. Il s'agit d'un modèle de conception de générateur en Lua.

local Config = {}
Config.__index = Config

function Config.new()
  return setmetatable({_data={}}, Config)
end

function Config:set(k,v) self._data[k]=v; return self end
function Config:build() return self._data end

local cfg = Config.new()
  :set("host","localhost")
  :set("port",8080)
  :set("debug",true)
  :build()

print(cfg.host, cfg.port)

Constructeur de copie

Un constructeur de copie crée une nouvelle instance avec les mêmes valeurs qu'une instance existante. Important : utilisez une copie superficielle ou profonde selon que les tables imbriquées doivent être partagées ou indépendantes.

local function deepCopy(orig)
  if type(orig)~="table" then return orig end
  local copy = {}
  for k,v in pairs(orig) do copy[deepCopy(k)]=deepCopy(v) end
  return setmetatable(copy, getmetatable(orig))
end

local Item = {}
Item.__index = Item

function Item.new(name, stats)
  return setmetatable({name=name, stats=stats or {}}, Item)
end

function Item:clone()
  return deepCopy(self)
end

local sword = Item.new("Sword",{damage=50})
local clone = sword:clone()
clone.stats.damage = 30
print(sword.stats.damage)  -- 50 (unchanged)

Constructeur avec validation

Validez toujours les entrées du constructeur. Déclenchez des erreurs descriptives pour les entrées invalides au niveau 2 (la responsabilité revient à l'appelant). Cela permet de détecter rapidement les bogues et de produire des messages d'erreur utiles.

local Rectangle = {}
Rectangle.__index = Rectangle

function Rectangle.new(w, h)
  assert(type(w)=="number" and w>0,"width must be positive number")
  assert(type(h)=="number" and h>0,"height must be positive number")
  return setmetatable({width=w, height=h}, Rectangle)
end

function Rectangle:area() return self.width * self.height end
function Rectangle:perimeter() return 2*(self.width+self.height) end

local r = Rectangle.new(5, 3)
print(r:area(), r:perimeter())  -- 15  16

Modèle des valeurs par défaut

Utilisez une table de valeurs par défaut pour gérer proprement les paramètres facultatifs du constructeur. Cela évite les longues chaînes de x = x or default et rend les valeurs par défaut explicites et faciles à modifier.

local Sprite = {}
Sprite.__index = Sprite

local DEFAULTS = {x=0,y=0,rotation=0,scale=1,visible=true,alpha=1}

function Sprite.new(image, opts)
  local cfg = opts or {}
  local self = {image=image}
  for k,v in pairs(DEFAULTS) do
    self[k] = cfg[k] ~= nil and cfg[k] or v
  end
  return setmetatable(self, Sprite)
end

local s = Sprite.new("hero.png",{x=100,y=200})
print(s.x,s.y,s.scale)  -- 100 200 1

Méthodes de fabrique statiques

Une classe peut disposer de plusieurs méthodes de fabrique pour différents scénarios de création. C'est plus propre que de surcharger un seul constructeur avec de nombreux paramètres facultatifs.

local Color = {}
Color.__index = Color

function Color.fromRGB(r,g,b)
  return setmetatable({r=r,g=g,b=b}, Color)
end

function Color.fromHex(hex)
  hex = hex:gsub("#","")
  return setmetatable({
    r=tonumber(hex:sub(1,2),16),
    g=tonumber(hex:sub(3,4),16),
    b=tonumber(hex:sub(5,6),16),
  }, Color)
end

function Color:toHex()
  return string.format("#%02X%02X%02X",self.r,self.g,self.b)
end

local red = Color.fromHex("#FF0000")
print(red:toHex())  -- #FF0000

Registre des constructeurs

Utilisez un registre pour suivre toutes les instances. Cela permet d'effectuer des opérations globales comme « détruire tout » ou de parcourir tous les objets d'un type donné.

local Enemy = {}
Enemy.__index = Enemy
Enemy._all = {}

function Enemy.new(name, hp)
  local self = setmetatable({name=name, hp=hp}, Enemy)
  Enemy._all[#Enemy._all+1] = self
  return self
end

function Enemy.destroyAll()
  for _, e in ipairs(Enemy._all) do
    print("Destroying:", e.name)
  end
  Enemy._all = {}
end

Enemy.new("Goblin",30)
Enemy.new("Orc",80)
print("Count:", #Enemy._all)  -- 2
Enemy.destroyAll()

Initialisation différée

Certains champs sont coûteux à calculer. Utilisez __index avec une fonction pour les calculer et les mettre en cache lors du premier accès.

local BigData = {}
BigData.__index = function(t, k)
  if k == "processed" then
    print("Computing processed...")
    local result = {}
    for i,v in ipairs(rawget(t,"raw")) do result[i]=v*2 end
    rawset(t,"processed",result)
    return result
  end
end

function BigData.new(raw)
  return setmetatable({raw=raw}, BigData)
end

local d = BigData.new({1,2,3,4,5})
print(d.processed[3])  -- Computing...  6
print(d.processed[3])  -- 6 (cached, no recompute)

Prototype à partir d'une instance

Clonez une instance pour en créer une autre avec les mêmes valeurs de base. Le clone reçoit la même métatable (la même classe) ainsi qu'une copie des données de l'instance. C'est utile pour les objets « modèles ».

local Unit = {}
Unit.__index = Unit

function Unit.new(t)
  return setmetatable({name=t.name,hp=t.hp,atk=t.atk}, Unit)
end

function Unit:clone()
  return Unit.new({name=self.name,hp=self.hp,atk=self.atk})
end

function Unit:__tostring()
  return self.name.."(HP:"..self.hp..",ATK:"..self.atk..")"
end

local template = Unit.new({name="Soldier",hp=100,atk=10})
local u1 = template:clone(); u1.name="Alpha"
local u2 = template:clone(); u2.name="Beta"
print(tostring(u1),tostring(u2))

Sécurité du constructeur en cas d'erreur

Si la construction échoue en cours de route (par exemple lors de l'allocation d'une ressource), veillez à ce qu'aucun objet partiellement créé ne s'échappe. Utilisez pcall pour intercepter les erreurs de construction et libérer les ressources si nécessaire.

local FileHandle = {}
FileHandle.__index = FileHandle

function FileHandle.new(path, mode)
  local f, err = io.open(path, mode or "r")
  if not f then
    return nil, "cannot open " .. path .. ": " .. err
  end
  return setmetatable({_f=f, path=path}, FileHandle)
end

function FileHandle:read(fmt) return self._f:read(fmt) end
function FileHandle:close() self._f:close() end

local fh, err = FileHandle.new("data.txt")
if not fh then print("Error:", err)
else print(fh:read("l")); fh:close()
end

Vérification rapide

Quel est le rôle d'un constructeur (new()) en POO Lua ?

Récapitulatif : constructeurs

Résumé :

  • Le constructeur valide, initialise et appelle setmetatable
  • Utilisez une table de valeurs par défaut pour gérer proprement les paramètres facultatifs
  • Utilisez plusieurs méthodes de fabrique pour différents scénarios de création
  • Utilisez un constructeur de clonage pour les objets modèles
  • Utilisez l'initialisation différée via __index pour les champs coûteux
  • En cas d'échec, renvoyez nil+err depuis le constructeur (allocation de ressource)

Questions Fréquemment Posées

La leçon « Constructeurs et new() » est-elle gratuite ?

Oui — le texte complet de « Constructeurs et new() » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Lua Academy, passe à CoddyKit PRO. Le cours Lua Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Constructeurs et new() » ?

Écrivez des fonctions constructrices qui créent et initialisent des instances. Tu pratiques Lua Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer Lua Academy ?

Aucune expérience préalable n'est requise. Lua Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.

Combien de temps prend la leçon « Constructeurs et new() » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon Lua Academy ?

Oui. Chaque leçon Lua Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Classes via les métatables
  2. Constructeurs et new()
  3. Méthodes d’instance et self
  4. Encapsulation avec des fermetures
← Retour à Lua Academy