Retour au cours

l'héritage : créer des hiérarchies de classes

Objectifs

  • Comprendre le principe de l’héritage et la relation “est un”.
  • Faire hériter une classe d’une autre en utilisant l’opérateur <.
  • Surcharger (override) une méthode de la classe parente.
  • Appeler la méthode du parent depuis la classe enfant avec super.
  • Savoir quand utiliser l’héritage et quand préférer un module (mixin).

Qu’est-ce que l’héritage ?

L’héritage est un mécanisme de la POO qui permet à une classe (la classe fille ou sous-classe) d’acquérir automatiquement toutes les méthodes et variables d’instance d’une autre classe (la classe mère ou super-classe).

L’héritage modélise une relation de type “est un”.

  • Un Chat est un Animal.
  • Une Voiture est un Vehicule.

La classe fille hérite de tout le comportement de la classe mère, et peut ensuite y ajouter ses propres spécificités ou modifier le comportement hérité.

Syntaxe de l’héritage

On utilise l’opérateur < pour indiquer qu’une classe hérite d’une autre.

# Classe mère (super-classe)
class Animal
  def manger
    puts "Je mange."
  end
  
  def dormir
    puts "Je dors."
  end
end

# La classe Chat hérite de la classe Animal
class Chat < Animal
  # La classe Chat a automatiquement accès à .manger et .dormir

  # On peut lui ajouter ses propres méthodes
  def miauler
    puts "Miaou !"
  end
end

mon_chat = Chat.new
mon_chat.manger  # => "Je mange." (méthode héritée)
mon_chat.miauler # => "Miaou !" (méthode propre)

Surcharger des méthodes et utiliser super

Une classe fille peut fournir sa propre implémentation d’une méthode qui existe déjà chez son parent. C’est la surcharge (overriding).

À l’intérieur d’une méthode surchargée, on peut vouloir appeler la version originale du parent. On utilise pour cela le mot-clé super. C’est très courant dans la méthode initialize.

class Vehicule
  attr_reader :nombre_de_roues

  def initialize(nombre_de_roues)
    @nombre_de_roues = nombre_de_roues
  end

  def description
    "Un véhicule à #{@nombre_de_roues} roues."
  end
end

class Voiture < Vehicule
  attr_reader :marque

  def initialize(marque)
    # On appelle l'initialize du parent (Vehicule)
    # pour qu'il s'occupe de la variable @nombre_de_roues.
    super(4)
    
    # Puis on s'occupe de nos propres initialisations.
    @marque = marque
  end
  
  # On surcharge la méthode description
  def description
    # On peut appeler la version du parent pour réutiliser son code
    description_parente = super
    "C'est une voiture de marque #{@marque}. #{description_parente}"
  end
end

ma_voiture = Voiture.new("Renault")
puts ma_voiture.description
# => "C'est une voiture de marque Renault. Un véhicule à 4 roues."

Héritage vs. Mixins (Modules)

  • Héritage : Modélise une relation “est un”. C’est une classification. Un Chat est un Animal. En Ruby, une classe ne peut hériter que d’une seule autre classe (héritage simple).
  • Mixin (avec include) : Modélise une capacité, une relation “peut faire” ou “a un”. Une Voiture et un Oiseau ne sont pas de la même famille, mais ils peuvent tous deux être Deplacable.

Règle générale : “Préférer la composition (et les mixins) à l’héritage”. L’héritage peut créer des hiérarchies de classes très rigides. Les mixins sont beaucoup plus flexibles. N’utilisez l’héritage que lorsque la relation “est un” est évidente et non ambiguë.

Exercices

  1. Hiérarchie simple :

    • Créez une classe Publication avec une méthode initialize qui accepte un titre et une méthode afficher qui affiche ce titre.
    • Créez une classe Livre qui hérite de Publication. Son initialize doit aussi accepter un auteur.
    • Créez une classe ArticleDeBlog qui hérite de Publication. Son initialize doit aussi accepter un nom_du_blog.
    • Instanciez un Livre et un ArticleDeBlog et appelez leur méthode afficher.
  2. Surcharge et super :

    • Dans la classe Livre, surchargez la méthode afficher pour qu’elle affiche "Livre : [titre] par [auteur]".
    • Dans la classe ArticleDeBlog, surchargez afficher pour qu’elle affiche "Article : [titre] (Blog : [nom_du_blog])".
    • Utilisez super si possible pour réutiliser une partie de la logique de la classe parente.
  3. Héritage ou Mixin ? :

    • Analysez les relations suivantes. Pour chacune, diriez-vous qu’elle relève de l’héritage ou d’un mixin ?
      • Carre et FormeGeometrique
      • Utilisateur, Commande et la capacité d’être “Exportable en PDF”
      • Manager et Employe
      • Velo, Voiture et la capacité d’avoir une “Couleur”