547 votes

Pourquoi utiliser attr_accessor, attr_reader et attr_writer de Ruby ?

Ruby a cette manière pratique et commode de partager des variables d'instance en utilisant des clés comme

attr_accessor :var
attr_reader :var
attr_writer :var

Pourquoi choisir attr_reader ou attr_writer si je peux simplement utiliser attr_accessor? Y a-t-il quelque chose comme les performances (ce que je doute)? Je suppose qu'il y a une raison, sinon ils n'auraient pas créé de telles clés.

2 votes

Possible duplicate de Qu'est-ce que attr_accessor en Ruby?

778voto

Wayne Conrad Points 31052

Vous pouvez utiliser les différents accessors pour communiquer votre intention à quelqu'un lisant votre code, et rendre plus facile l'écriture de classes qui fonctionneront correctement peu importe comment leur API publique est appelée.

class Personne
  attr_accessor :age
  ...
end

Ici, je peux voir que je peux à la fois lire et écrire l'âge.

class Personne
  attr_reader :age
  ...
end

Ici, je peux voir que je ne peux que lire l'âge. Imaginez que celui-ci soit défini par le constructeur de cette classe et reste constant par la suite. Si un mutateur (écrivain) pour l'âge existait et que la classe était écrite en supposant que l'âge, une fois défini, ne change pas, alors un bogue pourrait résulter de l'appel de ce mutateur par du code.

Mais que se passe-t-il en coulisses?

Si vous écrivez:

attr_writer :age

Cela se traduit par:

def age=(valeur)
  @age = valeur
end

Si vous écrivez:

attr_reader :age

Cela se traduit par:

def age
  @age
end

Si vous écrivez:

attr_accessor :age

Cela se traduit par:

def age=(valeur)
  @age = valeur
end

def age
  @age
end

Sachant cela, voici une autre façon de voir les choses : Si vous n'aviez pas les helpers attr_... et deviez écrire les accessors vous-même, écririez-vous plus d'accessors que votre classe n'en a besoin ? Par exemple, si l'âge avait seulement besoin d'être lu, écririez-vous aussi une méthode permettant de l'écrire ?

59 votes

Il y a aussi un avantage significatif en termes de performance à écrire attr_reader :a contre def a; return a; end confreaks.net/videos/…

85 votes

@Nitrodist, Intéressant. Pour Ruby 1.8.7, l'accesseur défini par attr_reader prend 86 % du temps que l'accesseur défini manuellement prend. Pour Ruby 1.9.0, l'accesseur défini par attr_reader prend 94 % du temps que l'accesseur défini manuellement prend. Dans tous mes tests, cependant, les accessoires sont rapides : un accessoire prend environ 820 nanosecondes (Ruby 1.8.7) ou 440 nanosecondes (Ruby 1.9). À ces vitesses, vous devrez appeler un accessoir des centaines de millions de fois pour que l'avantage de performance de attr_accessor améliore le temps d'exécution global même d'une seule seconde.

24 votes

"Probablement, il est défini par le constructeur de cette classe et reste constant." Ce n'est pas exact. Les variables d'instance avec des lecteurs peuvent changer fréquemment. Cependant, il est prévu que leurs valeurs ne soient modifiées que de manière privée par la classe.

28voto

hawx Points 693

Toutes les réponses ci-dessus sont correctes; attr_reader et attr_writer sont plus pratiques à écrire que de taper manuellement les méthodes pour lesquelles ce sont des raccourcis. En plus de cela, ils offrent des performances beaucoup meilleures que d'écrire vous-même la définition de la méthode. Pour plus d'informations, consultez la diapositive 152 et suivantes de cette présentation (PDF) par Aaron Patterson.

17voto

Chuck Points 138930

Tous les attributs d'un objet ne sont pas censés être directement définis depuis l'extérieur de la classe. Avoir des accesseurs pour toutes vos variables d'instance est généralement un signe d'encapsulation faible et un avertissement indiquant que vous introduisez trop de couplage entre vos classes.

Comme exemple concret : J'ai écrit un programme de conception où vous placez des éléments à l'intérieur de conteneurs. L'élément avait attr_reader :container, mais il n'était pas logique d'offrir un mutateur, puisque le seul moment où le conteneur de l'élément devrait changer est lorsqu'il est placé dans un nouveau conteneur, ce qui nécessite également des informations de positionnement.

14voto

coreyward Points 26109

Vous ne voulez pas toujours que vos variables d'instance soient entièrement accessibles depuis l'extérieur de la classe. Il y a de nombreux cas où il est logique de permettre l'accès en lecture à une variable d'instance, mais pas en écriture (par exemple, un modèle qui récupère des données à partir d'une source en lecture seule). Il existe des cas où vous voulez l'inverse, mais je ne peux pas en penser qui ne soient pas artificiels sur-le-champ.

0voto

nackjicholson Points 859

Parfois, vous voudrez peut-être éviter de violer la Loi de Demeter également. attr_writer serait préférable dans ce cas que attr_accessor.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X