POO en Ruby

Partie 1


non pas la POO !

La programmation orientée objet, ou POO, est un paradigme de programmation extrêmement utile dans lequel nous pouvons organiser notre code selon la façon dont les objets du monde réel peuvent interagir entre eux. Nous pouvons envelopper les propriétés/données et le comportement dans des classes, puis créer des instances, ou “membres” individuels, de ces classes qui peuvent interagir les unes avec les autres.

L’une des idées fausses les plus répandues au sujet de la POO est que tout DOIT modéliser le monde réel. Si nous limitons nos objets aux choses du monde réel, les limitations vont commencer à nous sauter aux yeux.

Imaginez un appel téléphonique entre 2 personnes. Bien sûr, les PERSONNES sont réelles, mais qu’en est-il de l’appel téléphonique ? Si nous pensons à l’appel téléphonique au travers de la POO, nous pouvons le modéliser aussi ! Un appel téléphonique a un émetteur et un destinataire, une durée et même un coût par minute. Dans le monde réel, ce n’est pas réel, mais dans la POO ça l’est !

Dans cet exemple, notre but est de créer une classe Livre simple. Nous voudrions qu’il ait des propriétés comme un titre, un auteur, un nombre de pages, etc. Nous aimerions aussi que la classe puisse, d’une façon ou d’une autre, garder une trace de tous les genres de tous les livres que nous créons. Enfin, nous donnerons à nos livres la capacité insensée totale de tourner leurs propres pages.

Definition de la classe Livre

Pour créer une nouvelle classe dans Ruby, nous utilisons le mot-clé class , suivi du nom d’une classe commençant par une majuscule. Définissons une classeBook dans un fichier book.rb: ( le code sera en anglais)

# book.rb

class Book
end
jusque la tout va bien ?

Bon essayons d’initialiser un nouveau livre (créer un nouveau livre) avec une forme comme ça :

Book.new("Lord of the Ring")
Ok! Billy …. là c’est tendu du slobard!

Je vais prendre des risques et deviner que “Lord of the Ring” est un titre, alors acceptons d’appeler cet argument title.

Mais comment passer un argument à l’initialisation exactement ? Entrez la méthode initialize!

Initialiser

La méthode d’initialisation est ce que l’on appelle un “hook” ou un “callback”. En d’autres termes, c’est une méthode qui se déclenche automatiquement lorsque quelque chose d’autre se produit. Dans le cas de l’initialisation, elle se déclenche lorsque nous appelons .new sur une classe. Il se trouve aussi que c’est la méthode à laquelle nous pouvons passer des arguments lors de l’initialisation d’une nouvelle instance d’une classe.

Ajoutons une méthode d’initialisation à notre classe livre, comme ceci :

# book.rb

class Book

def initialize(title)
end

end

Nous trouverons ce que nous devons faire avec le title dans une minute, mais pour l’instant, tout ce dont nous devons nous souvenir, c’est que la méthode initialize est un endroit où nous allons probablement faire de l’installation. Cool ?

Donner un titre a votre Livre

Il semble que nous n’ayons pas donner de titre à notre livre. Nous savons comment corriger cette erreur... on écrit juste du Ruby après tout!. Ecrivons la méthode titre dans notre classe Livre :

# book.rb

class Book

def initialize(title)
end

def title
end

end

nous sommes en train d’initialiser un livre avec “Lord of the Ring” comme argument, et puis, comme par magie, quand nous appelons title sur ce livre, il devrait retourner “Lord of the Ring”.

Cela signifie que quelque part entre appeler .new et .title, notre livre se voit attribuer un titre. Où est-ce que ça doit se passer, alors ?

Dans l méthode initialize Il n’y pas vraiment d’autre endroit.

Variables d’instance

C’est ici que les variables d’instance entrent en jeu. Les variables d’instance sont précédées d’un symbole “@” et sont dans le champ d’application d’une instance d’une classe. Cela signifie que n’importe quelle méthode au sein d’une instance a accès à n’importe quelle variable d’instance. C’est génial, parce qu’à l’intérieur de nos instances, nous n’avons pas à nous soucier de faire circuler les variables. Sympa, hein ?

Vous pouvez aussi, en quelque sorte, considérer les variables d’instance comme des propriétés d’une instance particulière d’une classe. Notre livre semble avoir une propriété de title, alors créons une variable d’instance @title pour lui ! C’est ce que nous allons faire avec la méthode d’initialisation.

# book.rb

class Book

def initialize(title)
@title = title
end

def title
end

end

Hmm….ça me dit quelque chose. Il semble que notre méthode de title renvoie nil.

Mais, attendez. Ne venons-nous pas de définir une variable d’instance, ou propriété, dans notre méthode d’initialisation ?

Nous l’avons fait, mais nous avons aussi oublié de l’utiliser d’une façon ou d’une autre. Si, lorsque nous appelons .title sur une instance de livre, nous sommes intéressés par sa propriété de titre, peut-être que nous devrions simplement retourner cette propriété, ou variable d’instance, dans cette méthode ?

Faisons cela (la différence est dans la méthode title) :

# book.rb

class Book

def initialize(title)
@title = title
end

def title
@title
end

end

Setter Method

Quoi ? Quoi ? Ça doit être une erreur, non ? Non, non.

Reculons une seconde. Cette méthode de title que nous avons déjà écrite est ce qu’on appelle un “getter”. Nous l’appelons ainsi parce que, eh bien, il “obtient” une propriété pour nous. Mais que se passe-t-il si nous voulons, disons, définir une propriété, ou une variable d’instance ? C’est là qu’interviennent les “setters”.

Les Setters sont des méthodes qui nous permettent de définir des variables d’instance. Cela semble bizarre, mais ils portent tous le nom suivant : property=. C’est parce que Ruby nous donne un joli morceau de sucre syntaxique qui nous permet d’utiliser ces méthodes comme :

instance.property = "something"

Cool, hein ?

Donc, si nous voulons donner un auteur à notre livre, il faut qu’il ait aussi une méthode de setter pour l’auteur. Ajoutons-en un à notre classe. Et, puisque nous savons tout sur les variables d’instance, allons de l’avant et définissons une variable d’instance, @authordans cette méthode :

# book.rb

class Book

def initialize(title)
@title = title
end

def title
@title
end

def author=(author)
@author = author
end

end

Setters et Getters habituellement (enfin, parfois, la plupart du temps, en quelque sorte) viennent en couple

Maintenant, on dirait qu’il nous manque une méthode auteur. Tout comme pour le title, si nous voulons accéder à une propriété de notre livre, nous avons besoin d’un getter pour cette propriété. C’est pour cette raison que les getters et les setters ont tendance à venir par paires. Ce n’est certainement pas une règle absolue, mais pour nos besoins actuels, c’est une règle générale que nous pouvons suivre.

Allons de l’avant et ajoutons le “getter” pour author à notre livre :

# book.rb

class Book

def initialize(title)
@title = title
end

def title
@title
end

def author=(author)
@author = author
end

def author
@author
end

end

Ok! maintenant c’est bon peut faire la même chose pour le nombre de page et le genre.

Attribute Accessors and Attribute Readers

This is where Attribute Accessors and Attribute Readers come into play.

C’est une explication très simpliste, mais voici ce qu’ils font:

Attribute Readers

  • Les lecteurs d’attributs nous donnent un getter, ou lecteur, gratuitement.
  • En d’autres termes, si nous avons un lecteur d’attributs (attr_reader) pour :name, Ruby va créer une méthode de namepour nous.

Attribute Accessors

  • Attribute accessors give us both a getter and a setter for free!
  • En d’autres termes, si nous avons un attribut d’accesseur(attr_accessor) pour:name, Ruby va créer les méthodes nameetname=pour nous.

Nous pouvons vraiment, vraiment simplifier notre code maintenant ! Puisque author, page_count, et genre ou les getters ne font rien de spécial (ils définissent juste des propriétés), nous pouvons les transformer en attr_accessors

# book.rb

class Book
attr_accessor :author, :page_count, :genre

def initialize(title)
@title = title
end

def title
@title
end

def turn_page
puts "Flipping the page...wow, you read fast!"
end

end

Notre title(ou getter) est aussi super basique, alors ajoutons un +attr_readerpour lui. Rappelez-vous, cela nous donnera une méthode de getter gratuitement !

# book.rb

class Book
attr_accessor :author, :page_count, :genre
attr_reader :title

def initialize(title)
@title = title
end

def turn_page
puts "Flipping the page...wow, you read fast!"
end

end
DONE !