Ruby en profondeur: Modules & Include vs Extend

Ruby fournit une construction appelée Module qui est un peu comme une classe mince. Au début, les développeurs Ruby pourraient regarder les modules comme un « tiroir indésirable » de code qui vient d’être jeté et utilisé pour organiser les fichiers, mais il existe une méthode à cette folie. La classe Ruby Class hérite de Module et ajoute des choses comme l’instanciation, les propriétés, etc. – tout ce que vous pensez normalement qu’une classe aurait. Parce que Module est littéralement un ancêtre de Class, cela signifie que les modules peuvent être traités comme des classes à certains égards.

Le plus important à comprendre est le fonctionnement de la chaîne d’ancêtres Ruby. Comme tous les langages OOP, Ruby prend en charge l’héritage. Lorsque vous héritez d’une classe, la superclasse est ajoutée à votre chaîne d’ancêtres. Vous pouvez afficher les ancêtres de n’importe quelle classe en appelant ancestors dessus:

class Foo < BarendFoo.ancestors#=> 

Comme mentionné, vous pouvez trouver Moduledans le tableau Class.ancestors.

Lorsque vous includeun module dans votre classe, le module est ajouté à la chaîne d’ancêtres de votre classe – tout comme une classe. Cela fait de include juste une forme d’héritage, il n’y a rien de spécial à ce sujet.

module Barendclass Foo include BarendFoo.ancestors#=> 

Toutes les méthodes de Bar sont ajoutées à Foo en tant que méthodes d’instance. Parce que Bar est dans la chaîne, vous pouvez même appeler super à partir de celle-ci pour appeler des méthodes au-dessus de celle-ci dans la chaîne, qu’elles soient définies sur des modules ou des classes.

class Baz def hello p 'world' endendmodule Bar def hello p 'hello' super endendclass Foo < Baz include BarendFoo.new.hello#=> hello world

Même si Bar est un module, super appelle toujours la chaîne et donc Baz#hello est également appelé. Il est à noter que Bar est ajouté à la chaîne d’ancêtres devant Baz. Lorsqu’un module est inclus, il est toujours ajouté directement au-dessus de sa classe d’inclusion. Cela peut être déroutant lors de l’ajout de plusieurs modules, car ils sont inclus dans l’ordre « inverse:

class Foo include A include BendFoo.ancestors#=> 

Lorsque A est inclus, il est inséré directement au-dessus de Foo. Mais lorsque B est inclus, il est également inséré directement au-dessus de Foo, il finit donc par atterrir avant A.

include vs extend

include est assez facile à comprendre, il ajoute les méthodes du module en tant que méthodes d’instance à sa classe d’inclusion. Vous pouvez penser à extend en faisant la même chose, mais en ajoutant les méthodes en tant que méthodes de classe.

module Bar def hello p 'hello' endendclass Foo extend BarendFoo.hello # no .new!# => 'hello'

prepend

En plus d’inclure/étendre, Ruby 2.0+ ajoute la méthode prependprepend est similaire à include, mais insère à la place le module avant la classe d’inclusion dans la chaîne d’héritage.

class Foo include Bar prepend BazendFoo.ancestors#=> 

Dans Ruby, vous pouvez rouvrir n’importe quelle classe et redéfinir les méthodes dessus – il ne semble pas utile de remplacer les méthodes d’une classe en utilisant un module ajouté au début plutôt que de les redéfinir. Où prepend est pratique, c’est lorsque vous avez toujours besoin de l’implémentation originale de la méthode, car les modules ajoutés au début peuvent remplacer les méthodes mais utilisent toujours super pour appeler l’implémentation d’origine.

Laisser un commentaire

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