Je suis assez familier avec l'utilisation des sous-classes et des modules, mais plus récemment, j'ai vu des classes imbriquées comme celle-ci:
class Foo
class Bar
# do some useful things
end
end
Ainsi que des classes imbriquées dans des modules comme ceci:
module Baz
class Quux
# more code
end
end
Soit la documentation et les articles sont rares, soit je ne suis pas suffisamment informé sur le sujet pour chercher les bons termes de recherche, mais je n'arrive pas à trouver beaucoup d'informations sur le sujet.
Quelqu'un pourrait-il fournir des exemples ou des liens vers des articles expliquant pourquoi / quand ces techniques seraient utilisées?
Car.new
etCar::Wheel.new
. Vous n'avez certainement pas besoin d'initialiser unCar
objet pour initialiser unCar::Wheel
objet dans Ruby, mais laCar
classe doit être chargée et exécutée pourCar::Wheel
être utilisable.Car
etCar::Wheel
. Les modules (et donc les classes) sont simplement des espaces de noms pour les constantes, il n'y a pas de classe imbriquée ou de module imbriqué dans Ruby.Car::Wheel.new
. Boom. Je viens de construire unWheel
objet qui n'est pas imbriqué dans unCar
objet.Dans Ruby, la définition d'une classe imbriquée est similaire à la définition d'une classe dans un module. Cela ne force pas réellement une association entre les classes, cela crée juste un espace de noms pour les constantes. (Les noms de classe et de module sont des constantes.)
La réponse acceptée n'était correcte sur rien. 1 Dans l'exemple ci-dessous, je crée une instance de la classe lexicalement incluse sans qu'une instance de la classe englobante n'existe jamais.
Les avantages sont les mêmes que ceux des modules: encapsulation, regroupement du code utilisé à un seul endroit, et rapprochement du code de l'endroit où il est utilisé. Un grand projet peut avoir un module externe qui se produit à plusieurs reprises dans chaque fichier source et contient un grand nombre de définitions de classe. Lorsque les différents frameworks et codes de bibliothèque font tous cela, ils ne fournissent qu'un seul nom chacun au niveau supérieur, ce qui réduit les risques de conflits. Prosaic, bien sûr, mais c'est pourquoi ils sont utilisés.
L'utilisation d'une classe au lieu d'un module pour définir l'espace de noms externe peut avoir du sens dans un programme ou un script à un fichier, ou si vous utilisez déjà la classe de niveau supérieur pour quelque chose, ou si vous allez réellement ajouter du code pour lier les classes entre elles dans un vrai style de classe interne . Ruby n'a pas de classes internes mais rien ne vous empêche de créer le même comportement dans le code. Référencer les objets externes à partir des objets internes nécessitera toujours un pointage à partir de l'instance de l'objet externe, mais l'imbrication des classes suggérera que c'est ce que vous pourriez faire. Un programme soigneusement modulaire peut toujours créer les classes englobantes en premier, et elles peuvent raisonnablement être décomposées avec des classes imbriquées ou internes. Vous ne pouvez pas appeler
new
un module.Vous pouvez utiliser le modèle général même pour les scripts, où l'espace de noms n'est pas terriblement nécessaire, juste pour le plaisir et la pratique ...
la source
B
n'est pas à l' intérieur de la classeA
. La constanteB
est nommée à l'intérieur de la classeA
, mais il n'y a absolument aucune relation entre l'objet référencé parB
(qui dans ce cas se trouve être juste une classe) et la classe référencée parA
.You can't call new on a module.
- donc en termes simples si je veux juste mettre en espace des noms de classes et ne jamais avoir besoin de créer une instance de la "classe" externe, alors J'utiliserais un module externe. Mais si je veux instancier une instance de la «classe» enveloppante / externe, alors j'en ferais une classe au lieu d'un module. Au moins, cela a du sens pour moi.Vous souhaiterez probablement l'utiliser pour regrouper vos classes dans un module. Une sorte d'espace de noms.
par exemple, le gem Twitter utilise des espaces de noms pour y parvenir:
Donc, les deux
Client
et lesSearch
classes vivent sous leTwitter
module.Si vous souhaitez vérifier les sources, le code des deux classes peut être trouvé ici et ici .
J'espère que cela t'aides!
la source
Il y a encore une autre différence entre les classes imbriquées et les modules imbriqués dans Ruby avant la version 2.5 que d'autres réponses n'ont pas réussi à couvrir et qui, selon moi, doivent être mentionnées ici. C'est le processus de recherche.
En bref: en raison de la recherche constante de niveau supérieur dans Ruby avant la version 2.5, Ruby peut finir par rechercher votre classe imbriquée au mauvais endroit (
Object
en particulier) si vous utilisez des classes imbriquées.Dans Ruby antérieur à 2.5:
Structure de classe imbriquée: supposons que vous ayez une classe
X
, avec une classe imbriquéeY
, ouX::Y
. Et puis vous avez une classe de haut niveau nommée égalementY
. SiX::Y
n'est pas chargé, alors ce qui suit se produit lorsque vous appelezX::Y
:N'ayant pas trouvé
Y
dansX
, Ruby essaiera de le rechercher dans les ancêtres deX
. PuisqueX
est une classe et non un module, elle a des ancêtres, parmi lesquels[Object, Kernel, BasicObject]
. Donc, il essaie de chercherY
dansObject
, où il le trouve avec succès.Pourtant, c'est le plus haut niveau
Y
et nonX::Y
. Vous recevrez cet avertissement:Structure de module imbriqué: Supposons que dans l'exemple précédent
X
soit un module et non une classe.Un module n'a que lui-même comme ancêtre:
X.ancestors
produirait[X]
.Dans ce cas, Ruby ne pourra pas rechercher
Y
dans l'un des ancêtres deX
et lancera un fichierNameError
. Rails (ou tout autre framework avec chargement automatique) essaiera de se chargerX::Y
après cela.Voir cet article pour plus d'informations: https://blog.jetbrains.com/ruby/2017/03/why-you-should-not-use-a-class-as-a-namespace-in-rails-applications/
In Ruby 2.5:
Suppression de la recherche constante de niveau supérieur.
Vous pouvez utiliser des classes imbriquées sans craindre de rencontrer ce bogue.
la source
En plus des réponses précédentes: Le module en Ruby est une classe
la source
new
. Donc, bien que vous puissiez dire que les modules sont une classe (minuscules), ils ne sont pas la même chose qu'une classe (majuscules) :)