Contrôle d'accès
Plus haut, nous avons dit que ruby n’a pas de fonctions, seulement des méthodes. Oui, mais il y a plusieurs sortes de méthodes. Dans ce chapitre, nous introduisons les contrôles d’accès.
Considérons ce qui arrive quand nous définissons une méthode au niveau le plus élevé, pas dans une définition de classe. On peut penser à une telle méthode comme analogue à une fonction telle qu’on en définit dans des langages plus traditionnels tel que C.
ruby> def carré(n)
| n * n
| end
nil
ruby> carré(5)
25
Notre nouvelle méthode pourrait apparaître comme n’appartenant à aucune classe, mais en fait ruby l’affecte à la classe Object, qui est super-classe de toutes les classes. En conséquence, tout objet pourrait alors utiliser cette méthode. Et c’est vrai, mais avec une petite restriction : c’est une méthode privée de toute classe. On verra plus bas ce que cela signifie, mais une des conséquences est que cette méthode ne peut être invoquée qu’à la façon d’une fonction, comme ici :
ruby> class Foo
| def quatrième_puissance_de (x)
| carré(x) * carré(x)
| end
| end
nil
ruby> Foo.new.quatrième_puissance_de 10
10000
On n’a pas le droit d’appliquer explicitement la méthode à un objet :
ruby> "fish".carré(5)
ERR: (eval):1: private method `carré' called for "fish":String
Ceci préserve intelligemment la nature purement orientée objet de ruby (les fonctions sont encore des méthodes, mais le receveur est implicitement self tout en fournissant des fonctions qui peuvent être écrites comme dans un langage classique.
Une discipline mentale courante en programmation orientée objet, que nous avons rencontrée plus tôt, concerne la séparation de la spécification et de l’implémentation, autrement dit du quoi et du comment : quelles tâches un objet est supposé accomplir et comment il les accomplit. Le fonctionnement interne d’un objet devrait généralement être caché aux yeux de ses utilisateurs, qui ne devraient avoir à s’occuper que de ce qui entre et sort de l’objet, et se fier à l’objet pour savoir ce qu’il a à faire en interne. De ce fait, il est souvent utile que des classes aient des méthodes que le monde extérieur ne voit pas, mais qui sont utilisées en interne (et peuvent être améliorées par le programmeur de la méthode autant qu’il veut, sans affecter la façon dont les utilisateurs voient les objets de cette classe). Dans l’exemple trivial ci-dessous, imaginez que moteur est ce qui travaille dans la classe sans être vu.
ruby> class Test
| def fois_deux(a)
| print a," fois deux font ",moteur(a),"n"
| end
| def moteur(b)
| b*2
| end
| private:moteur # ceci cache le moteur aux yeux des
| # utilisateurs
| end
Test
ruby> test = Test.new
#<Test:0x4017181c>
ruby> test.moteur(6)
ERR: (eval):1: private method `moteur' called for #<Test:0x4017181c>
ruby> test.fois_deux(6)
6 fois deux font 12.
nil
On aurait peut-être attendu que test.moteur(6) rende 12, mais au lieu de ça on apprend que moteur est inaccessible quand on agit comme utilisateur d’un objet de type Test. Seules les autres méthodes Test comme fois_deux, ont le droit d’utiliser moteur. Nous devons passer par l’interface publique, qui consiste en la méthode fois_deux. Le programmeur qui a la charge de cette classe peut changer moteur librement (ici, par exemple, en remplaçant b*2 par b+b, par exemple pour augmenter les performances) sans affecter la façon dont l’utilisateur interagira avec les objets de type Test. Cet exemple est évidemment trop simpliste pour être utile, et les bénéfices des contrôles d’accès n’apparaîtront clairement que lorsque nous commencerons à créer des classes plus compliquées et plus intéressantes.
Précédent : GDU : Redéfinition des méthodes Suivant : GDU : Méthodes singletons


