Menu
Coddy logo textTech

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.

challenge icon

Défi

Facile

Construisons 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 utilitaire applyMixin. Lisez le nom de l’oiseau et indiquez s’il sait nager (yes ou no). 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 :

  1. Le nom de l’oiseau (une chaîne de caractères)
  2. Indique si l’oiseau sait nager : yes ou no

Si l’oiseau sait nager, votre sortie doit être :

{name} is eating
{name} chirps!
{name} is swimming

Si 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 swimming

Si 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
quiz iconTestez-vous

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

Entraînez-vous par vous-même : Compilateur Lua en ligne