Méthodes de Classe Privée Ruby

24 Jan 2016

Dans le langage de programmation Ruby, les méthodes définies se déclinent en deux variantes : les méthodes d’instance et les méthodes de classe. Les méthodes d’instance sont disponibles après l’initialisation d’un objet, créant une instance. Les méthodes de classe, en revanche, sont disponibles sans créer d’instance de la classe sur laquelle elles sont définies.

La visibilité des méthodes Ruby peut varier. Les méthodes publiques sont disponibles dans n’importe quel contexte, tandis que la disponibilité des méthodes privées est limitée dans l’instance d’une classe et de ses descendants. Une troisième portée de visibilité, protected, se comporte de la même manière que les méthodes privées, mais les méthodes protégées peuvent être appelées par d’autres instances de la même classe.

Pour une mise à jour rapide, les méthodes d’instance publique et privée ressemblent à ceci:

class Dog def do_trick bark end private def bark puts 'woof woof' endend

Lorsque la méthode publique est appelée:

> dog = Dog.new> dog.do_trick# => woof woof

Et la méthode privée:

> dog = Dog.new> dog.bark# => NoMethodError: private method `bark' called for <Dog>

Les méthodes de classe privée peuvent ne pas être aussi courantes que les méthodes d’instance privée, mais elles ont toujours leur place. Par exemple, une méthode de classe peut nécessiter des méthodes d’assistance internes pour compléter sa fonction. Quelle que soit la raison, la définition de méthodes de classe privée a de la valeur mais n’est pas toujours intuitive.

Cet exemple de classe Dog doit conserver une liste de tricks qui seront utilisées dans les autres méthodes de classe publique. Cette liste ne doit pas être accessible aux appelants en dehors de la classe Dog.

Dans le mauvais sens

Une première passe à l’écriture de la méthode privée tricks pourrait ressembler à:

class Dog private def self.tricks endend

Cependant, lors du test de la visibilité de la méthode tricks:

> Dog.tricks# => 

Euh oh, aucune erreur n’a été lancée indiquant qu’une méthode privée a été appelée, cette méthode est complètement publique.

Pourquoi?

La raison pour laquelle le code ci-dessus n’a pas produit de méthode privée est liée à la hiérarchie d’objets de Ruby, aux interactions entre les classes internes, aux instances de ces classes et aux classes propres. Un article détaillé sur le fonctionnement des objets Ruby les uns avec les autres se trouve dans un article précédent.

Lors de la définition de méthodes dans une classe, le contexte par défaut et le contexte introduit par la déclaration de méthode self. sont distincts.

La portée de la méthode privée ne peut pas être utilisée de la manière ci-dessus car elle ne gère pas le changement de contexte entre les méthodes définies sur la classe Dog et définies dans le contexte self.

Alors quelles sont les alternatives?

class < < self

Une autre façon de définir des méthodes de classe sur un objet consiste à utiliser la syntaxe class << self. Cette syntaxe ouvre une classe propre pour l’argument fourni. Dans cet exemple, self dans la classe Dog ouvrira la classe propre Dog's.

class Dog class << self private def tricks end endend

Une chose à noter est que lors de la définition de méthodes comme celle-ci, la déclaration est passée de def self.tricks à simplement def tricks.

Maintenant, la portée privée est préservée et le comportement attendu est atteint:

> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class

Modules

Les modules de ruby sont des collections de méthodes et de constantes. Ces collections peuvent être utilisées comme outils d’encapsulation ou, dans ce cas, comme alternatives à la définition de méthodes de classes publiques et privées.

Lorsqu’une classe extends un module, toutes les méthodes de ce module deviennent des méthodes de classe sur la classe de sujet *. Ce modèle peut être utilisé pour définir la méthode tricks sur Dog.

* Remarque: Cela ne concerne que les méthodes définies dans un « sens typique », les définitions de méthodes def self. ou def Dog. dans un module ne deviennent pas automatiquement des méthodes de classe de la même manière lorsque extended.

class Dog module ClassMethods private def tricks end end extend ClassMethodsend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class

Un avantage de cette approche est la lisibilité. Le module nommé ClassMethods, qui est contenu et donc encapsulé par la classe Dog, est la maison claire pour toutes les méthodes de classe souhaitées.

Les modificateurs de visibilité comme private se comportent en conséquence et un simple extend au bas de la définition du module rassemble tout cela.

private_class_method

Une troisième approche consiste à utiliser la méthode intégrée Module#private_class_method. Le but de cette méthode est de modifier la visibilité des méthodes de classe existantes.

Contrairement aux deux autres solutions, celle-ci ne nécessite pas un style de définition de méthode différent de la solution incorrecte:

class Dog def self.tricks end private_class_method :tricksend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class

Cette méthode peut également être intégrée lors de la définition de la méthode de la classe:

class Dog private_class_method def self.tricks endend> Dog.tricks# => NoMethodError: private method `tricks' called for Dog:Class

Si une méthode de classe unique doit être privée et que l’enregistrement de lignes est très important, ce style peut être applicable; mais, il sacrifie certainement un niveau de lisibilité.

Une force majeure de private_class_method est son caractère explicite. Contrairement aux autres approches, celle-ci ne nécessite pas de définition de module ou de commutation de contexte de définition de méthode spéciale.

Lectures supplémentaires

Les solutions susmentionnées feront le travail, mais pourraient ne pas répondre aux questions persistantes sur les raisons pour lesquelles les choses fonctionnent comme elles le font. Quelques excellents articles sur la classe propre ruby et les réflexions de Matz sur la conception de la méthode Ruby devraient aider à brosser un tableau plus concis des raisons pour lesquelles la définition de la méthode de classe privée de Ruby est complexe.

You might also like

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.