Mixins vs Héritage
Fait partie de la section Programmation orientée objet du Journey Lua de Coddy. Leçon 53 sur 70.
Tu as appris deux façons de partager un comportement : l’héritage crée une relation « est-un » via la chaîne des prototypes, tandis que les mixins copient directement des fonctions dans une classe. Mais quand dois-tu utiliser chaque approche ?
Utilisez l’héritage lorsque les objets partagent une identité fondamentale. Un Bird est un Animal. Il est logique que Bird hérite des comportements fondamentaux des animaux, comme :eat() ou :sleep(). La relation est permanente et définit ce que l’objet est fondamentalement.
Utilisez des mixins lorsque vous souhaitez ajouter une capacité qui ne définit pas l’identité fondamentale de l’objet.
Tous les oiseaux ne peuvent pas voler : les manchots et les autruches sont des oiseaux, mais ils ne volent pas. Voler est une capacité, et non un trait définissant le fait d’être un oiseau. Un mixin Flyable vous permet d’ajouter le vol aux oiseaux qui en ont besoin, sans l’imposer à tous.
Les deux approches fonctionnent parfaitement ensemble :
-- Bird hérite de Animal (relation is-a)
local Bird = {}
Bird.__index = Bird
setmetatable(Bird, {__index = Animal})
-- Flyable est une capacité (mixin)
local Flyable = {}
function Flyable:fly()
print(self.name .. " soars through the sky!")
end
-- Appliquer le mixin uniquement aux oiseaux qui peuvent voler
applyMixin(Bird, Flyable)Ce modèle vous offre le meilleur des deux mondes : une hiérarchie de classes claire pour une identité partagée, ainsi que des capacités flexibles qui peuvent être combinées là où c’est nécessaire.
Défi
FacileConstruisons un petit écosystème de créatures qui montre quand utiliser l’héritage plutôt que les mixins ! Vous allez créer une classe de base Animal, un Bird qui en hérite, ainsi qu’un mixin Swimmable, car si tous les oiseaux sont des animaux, tous les oiseaux ne savent pas nager.
Vous organiserez votre code sur quatre fichiers :
Animal.lua: créez la classe de base Animal avec un constructeur:new(name)qui stocke le nom. Incluez une méthode:eat()qui affiche{name} is eating. Cela représente l’identité fondamentale que partagent tous les animaux.Swimmable.lua: créez un mixin avec une méthode:swim()qui affiche{self.name} is swimming. Il s’agit d’une capacité : toutes les créatures ne savent pas nager, elle ne doit donc pas faire partie de la chaîne d’héritage.Bird.lua: créez une classe Bird qui hérite de Animal. Le constructeur:new(name, canSwim)doit appeler le constructeur parent et stocker si cet oiseau sait nager. Appliquez le mixin Swimmable à la classe Bird. Incluez une méthode:chirp()qui affiche{name} chirps!. Il s’agit d’un comportement propre aux oiseaux.main.lua: écrivez ici la fonction utilitaireapplyMixin. Lisez le nom de l’oiseau et indiquez s’il sait nager (yesouno). Créez une instance de Bird, puis démontrez ses capacités : appelez:eat()(héritée de Animal), appelez:chirp()(la propre méthode de Bird), et appelez:swim()uniquement si l’oiseau sait nager.
Vous recevrez deux entrées :
- Le nom de l’oiseau (une chaîne de caractères)
- Indique si l’oiseau sait nager :
yesouno
Si l’oiseau sait nager, votre sortie doit être :
{name} is eating
{name} chirps!
{name} is swimmingSi l’oiseau ne sait pas nager, votre sortie doit être :
{name} is eating
{name} chirps!Par exemple, si les entrées sont Duck et yes, la sortie doit être :
Duck is eating
Duck chirps!
Duck is swimmingSi les entrées sont Sparrow et no, la sortie doit être :
Sparrow is eating
Sparrow chirps!Ce défi montre la distinction essentielle : Bird est un Animal (héritage), mais la nage est une capacité facultative (mixin). Le mixin est appliqué à la classe, mais votre logique principale décide de l’utiliser ou non en fonction des capacités de chaque oiseau !
Essayez vous-même
-- main.lua: Point d'entrée - créer un oiseau et démontrer ses capacités
-- Fonction d'aide pour appliquer un mixin à une classe
local function applyMixin(class, mixin)
-- TODO: Copier toutes les méthodes du mixin vers la classe
end
-- Appliquer le mixin Swimmable à Bird avant de requérir Bird
-- Note: Vous devrez peut-être gérer ceci dans Bird.lua ou ici
local Bird = require('Bird')
local Swimmable = require('Swimmable')
-- Appliquer le mixin à la classe Bird
applyMixin(Bird, Swimmable)
-- Lire les entrées
local name = io.read()
local canSwimInput = io.read()
-- TODO: Déterminer si l'oiseau peut nager d'après l'entrée ("yes" ou "no")
-- TODO: Créer une instance de Bird avec le nom et la capacité de nage
-- TODO: Appeler eat() - hérité de Animal
-- TODO: Appeler chirp() - méthode propre de Bird
-- TODO: N'appeler swim() que si l'oiseau peut nager
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation orientée objet
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 RectangleClasse CercleMéthode PérimètreCollection de formesAire totaleFiltrer les formes2Modè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 robotsEntraînez-vous par vous-même : Compilateur Lua en ligne