TUTORIEL OUTILS 
La gestion Objet au sein du langage Ruby
L'approche des classes et de l'héritage par Ruby peut surprendre, mais révèle un langage très élégant et logique dans ses approches. (18/11/2005)
Nous l'avions déjà précisé à propos de la syntaxe (lire notre article du 25/08/05), Ruby est un langage "tout Objet" : un simple chiffre représente en fait une occurrence de la classe Integer (Fixnum, ou Bignum pour les grands nombres). Nous allons donc voir comme Ruby présente la gestion Objet au développeur...

Ruby a été conçu pour offrir un support Objet à la fois complet et extensible - on pourra par exemple ajouter des méthodes à une occurrence de classe sans que les autres occurrences soient affectées.

Classes
Nous avons déjà vu comment utiliser les méthodes existantes. Par exemple, la classe Integer fournit un méthode next, qui pourra s'appeller sous ces formes :

puts 1.next  # affiche la valeur 2
puts 1.next.next  # affiche la valeur 3


Nous avions également vu comment ajouter des méthodes aux classes :

class Float
  def jeMange
    "Vous ne voyez pas que je mange ?"
  end
end
puts 3.14159265.jeMange  
# affiche le chaîne "Vous ne voyez pas que je mange ?"


Cela nous présente par la même occasion la méthode de création de classe personnelle : plutôt que d'ajouter des méthodes à des classes existantes, il peut être plus pratique de se créer ses propres classes, en rapport avec le contexte de l'application. Par exemple, si nous devons gérer un lecteur MP3 :

class LecteurMP3
  def chargerFichier(chemin, fichier)
    # ...
  end
  def jouerFichier(fichier)
    # ...
  end
  def fermerFichier(fichier)
    # ...
  end
end


À partir de là, on pourra instancier notre classe en un objet spécifique :

monLecteur = LecteurMP3.new('lapin')
monLecteur.chargerFichier('/musique', 'stfu.ogg')
monLecteur.jouerFichier('stfu.ogg')


Le constructeur d'une classe Ruby ne se créé pas en ayant une méthode du même nom que la classe, mais au travers d'une méthode à part, initalize. Celle-ci peut prendre en compte certains arguments clefs, et est généralement utilisée pour assigner ces arguments à des variables d'instance (c'est à dire, des variables propres à l'objet, ou plus simplement ses attributs) :

class LecteurMP3
  def initialize(chemin)
    @chemin = chemin
    @lectureEnCours = false
    puts 'Bienvenue dans LecteurMP3 v0.0.1.0'
  end
  def chargerFichier(fichier)
    leChemin = @chemin + fichier
    ...

monLecteur = LecteurMP3.new('lapin')
monLecteur.chargerFichier('stfu.ogg')


initialize est donc appellé à chaque instanciation de LecteurMP3. Le caractère @, placé devant un nom de variable, indique que celle-ci est une variable d'instance.

Héritage
Comme tout bon langage orienté Objet, Ruby autorise l'héritage, afin de dériver et spécialiser les classes. Il faut savoir que Ruby n'autorise que l'héritage simple, comme Java, c'est-à-dire qu'une classe ne peut hériter que d'une seule autre classe (à la différence de l'héritage multiple). C'est une conception voulue, et l'héritage multiple peut être suppléé par des modules, ou "mixins", c'est-à-dire des groupements de méthodes.

Voyons déjà comment entreprendre l'héritage :

class Femme < Humain
  def initalize(prenom, nom, dateNaissance)
    super(prenom, nom, dateNaissance)
    @sexe = f
  end
  ...


Le signe "plus petit que" fait ici office de "flèche" pour indiquer que Femme descend de Humain, et donc récupère ses méthodes. Grâce à super(), on passe certains arguments à la méthode initialize de la classe parente, afin qu'ils soient correctement traités.

Les modules diffèrent des classes en cela que les méthodes qu'ils contiennent ne forment pas naturellement une classe. Les méthodes d'une classe ont toutes la classe en commun, une sorte de contexte global qui les relie. Les modules peuvent de leur côté contenir toutes sortes de méthodes, sans qu'elles soient forcément liées. Les modules ne peuvent pas être instanciés.

module Zorglub
  CONSTANTE = 42
  def Zorglub.uneFonction
    # ...
   end
end


Le module a l'avantage, face à un simple fichier externe de codes variés, de fournir un espace de nom unique aux fonctions qu'il contient. Cela permet d'éviter le cas où deux groupes de méthodes chargés entrent en conflit pour cause de noms de méthodes identiques.

require zorglub
laReponse = Zorglub::CONSTANTE
bidule = Zorglub.uneFonction


Les modules peuvent suppléer efficacement à l'héritage multiple par le biais de "mixins". Un module ne peut être instancié, mais il peut être appelé directement depuis le corps d'une classe, ce qui fournit l'ensemble de ses méthodes à la classe appelante. Dans les faits, les modules "ajoutés" à une classe se comportent de la même manière que le ferait une super normale. Il devient donc possible de définir des méthodes d'instance au sein d'un module.

class GrandMechantEvilGrave
  include Zorglub
  # ...
end


Ainsi, tout en restant un langage à héritage simple, Ruby peut profiter de manière élégante de tous les avantages de l'héritage multiple.
 
Xavier Borderie, JDN Développeurs
 
Accueil | Haut de page
 
 





Quand achetez-vous le plus en ligne ?
Du lundi au vendredi
Le samedi
Le dimanche

Tous les sondages