Appliquer plusieurs Mixins
Fait partie de la section Object Oriented Programming du Journey Lua de Coddy — leçon 52 sur 70.
Un seul mixin ajoute un ensemble de comportements à une classe. Mais les objets réels ont souvent besoin de capacités provenant de sources multiples. Un objet de jeu peut avoir besoin de se déplacer et d'être visible à l'écran — deux préoccupations distinctes qui n'ont pas leur place dans le même mixin.
La solution est simple : appliquez plusieurs mixins à la même classe. Chaque mixin apporte ses propres méthodes, et la classe finit par toutes les posséder :
local Movable = {}
function Movable:move(dx, dy)
self.x = self.x + dx
self.y = self.y + dy
end
local Visible = {}
function Visible:show()
print("Showing at " .. self.x .. ", " .. self.y)
end
function Visible:hide()
print("Hidden")
endAppliquez les deux mixins à votre classe en utilisant la même fonction utilitaire que précédemment :
local function applyMixin(class, mixin)
for key, value in pairs(mixin) do
class[key] = value
end
end
local GameObject = {}
GameObject.__index = GameObject
applyMixin(GameObject, Movable)
applyMixin(GameObject, Visible)Désormais, les instances de GameObject peuvent à la fois se déplacer et s'afficher :
local obj = setmetatable({x = 0, y = 0}, GameObject)
obj:move(5, 3)
obj:show() -- Affichage à 5, 3Une mise en garde : si deux mixins définissent le même nom de méthode, le second appliqué écrasera le premier. Gardez vos méthodes de mixin distinctes pour éviter tout comportement inattendu.
Défi
FacileConstruisons une classe Character pour un jeu qui combine plusieurs capacités en utilisant des mixins ! Votre personnage sera capable à la fois d'attaquer des ennemis et de se soigner lui-même — deux comportements distincts provenant de mixins séparés.
Vous organiserez votre code sur quatre fichiers :
Attacker.lua: Créez un mixin avec une méthode:attack(targetName)qui affiche{self.name} attacks {targetName} for {self.damage} damage!(suppose que l'objet possède les champsnameetdamage)Healer.lua: Créez un mixin avec une méthode:heal(amount)qui ajoute le montant àself.healthet affiche{self.name} heals for {amount}. Health: {newHealth}Character.lua: Créez une classe Character avec un constructeur:new(name, health, damage)qui stocke les trois attributs. Appliquez les mixins Attacker et Healer pour que chaque personnage puisse attaquer et soigner. Incluez une méthode:status()qui affiche{name} - Health: {health}, Damage: {damage}main.lua: Écrivez la fonction utilitaireapplyMixinici. Lisez les entrées pour le nom d'un personnage, sa santé, ses dégâts, une cible à attaquer et un montant de soin. Créez un Character, affichez son statut, faites-lui attaquer la cible, soignez-le, puis affichez à nouveau son statut.
Vous recevrez cinq entrées :
- Nom du personnage (une chaîne de caractères)
- Santé de départ (un nombre)
- Valeur des dégâts (un nombre)
- Nom de la cible à attaquer (une chaîne de caractères)
- Montant à soigner (un nombre)
Votre sortie devrait montrer le personnage utilisant les deux capacités des mixins :
{name} - Health: {health}, Damage: {damage}
{name} attacks {target} for {damage} damage!
{name} heals for {healAmount}. Health: {newHealth}
{name} - Health: {newHealth}, Damage: {damage}Par exemple, si les entrées sont Warrior, 100, 25, Goblin, et 30, la sortie devrait être :
Warrior - Health: 100, Damage: 25
Warrior attacks Goblin for 25 damage!
Warrior heals for 30. Health: 130
Warrior - Health: 130, Damage: 25Chaque mixin apporte sa propre méthode à la classe Character. Le personnage n'hérite d'aucun des mixins — il acquiert simplement leurs capacités via la fonction applyMixin. C'est toute la puissance de la combinaison de plusieurs mixins !
Aide-mémoire
Plusieurs mixins peuvent être appliqués à une seule classe pour combiner différents ensembles de comportements. Chaque mixin apporte ses propres méthodes à la classe.
Définissez des mixins distincts pour différentes préoccupations :
local Movable = {}
function Movable:move(dx, dy)
self.x = self.x + dx
self.y = self.y + dy
end
local Visible = {}
function Visible:show()
print("Showing at " .. self.x .. ", " .. self.y)
end
function Visible:hide()
print("Hidden")
endAppliquez plusieurs mixins à une classe en utilisant la fonction utilitaire applyMixin :
local function applyMixin(class, mixin)
for key, value in pairs(mixin) do
class[key] = value
end
end
local GameObject = {}
GameObject.__index = GameObject
applyMixin(GameObject, Movable)
applyMixin(GameObject, Visible)La classe possède désormais les méthodes de tous les mixins appliqués :
local obj = setmetatable({x = 0, y = 0}, GameObject)
obj:move(5, 3)
obj:show() -- Showing at 5, 3Important : Si deux mixins définissent le même nom de méthode, le deuxième mixin appliqué écrasera le premier. Gardez les noms de méthodes distincts entre les mixins pour éviter les conflits.
Essayez vous-même
-- Fichier principal
-- TODO: Écrire la fonction auxiliaire applyMixin
-- Cette fonction doit copier toutes les méthodes d'une table mixin vers une table cible
local function applyMixin(target, mixin)
-- TODO: Implémenter l'application du mixin
end
-- Rendre applyMixin disponible globalement pour que Character.lua puisse l'utiliser
_G.applyMixin = applyMixin
local Character = require('Character')
-- Lire les entrées
local name = io.read()
local health = tonumber(io.read())
local damage = tonumber(io.read())
local targetName = io.read()
local healAmount = tonumber(io.read())
-- TODO: Créer un Personnage avec le nom, la santé et les dégâts donnés
-- TODO: Afficher le statut du personnage
-- TODO: Faire en sorte que le personnage attaque la cible
-- TODO: Faire en sorte que le personnage se soigne lui-même
-- TODO: Afficher à nouveau le statut du personnage
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Object Oriented Programming
1Le concept de « self »
Tables avec fonctions« self » expliciteLa syntaxe avec deux-pointsPoint vs deux-pointsRécapitulatif - Point mobile4Projet : Banque numérique
Configuration du projetMéthode de dépôt7Polymorphisme et Redéfinition
Redéfinition de méthodesAppeler des méthodes parentesDuck TypingInterface communeVérification du typeRécapitulatif - Rôles des employés10Projet : Gestionnaire de formes
Configuration du projetClasse Rectangle2Modèle de prototype de classe
Le concept de prototypeLiaison avec __indexLe constructeur :new()Initialisation des attributsInstances indépendantesRécapitulatif - Usine de voitures5Surcharge d'opérateurs en POO
Additionner des objetsSoustraire des objetsConcaténer des objetsComparer des objets (<, >)Récapitulatif - Calculs de portefeuille8Encapsulation
Conventions de nommageClosures pour la confidentialitéAccès via les ClosuresTables en lecture seuleLogique de validationRécapitulatif - Coffre-fort sécurisé11Patrons de conception (Lite)
Fonctions FactoryTable SingletonPatron IteratorObserver (Écouteur)Récapitulatif - Logger Factory3État et comportement des objets
Variables d'instanceMéthodes GetterMéthodes SetterPropriétés calculéesFormatage de chaînesVérifications d'égalitéRécapitulatif - Note de l'étudiant6Bases de l'héritage
Mise en place de l'héritageHériter des méthodesÉtendre le constructeurAjouter des méthodes enfantsPartagé vs UniqueRécapitulatif - Hiérarchie des formes9Composition et Mixins
Relation 'A un'DélégationMixins simplesAppliquer plusieurs MixinsMixins vs HéritageRécapitulatif - Assemblage de robots