Estoy bastante familiarizado con cuándo usar subclases y módulos, pero más recientemente he estado viendo clases anidadas como esta:
class Foo
class Bar
# do some useful things
end
end
Además de clases anidadas en módulos de esta manera:
module Baz
class Quux
# more code
end
end
O bien la documentación y los artículos son escasos o no estoy bien informado sobre el tema para buscar los términos de búsqueda correctos, pero parece que no puedo encontrar mucha información sobre el tema.
¿Podría alguien proporcionar ejemplos o enlaces a publicaciones sobre por qué / cuándo se utilizarían esas técnicas?
Car.new
yCar::Wheel.new
. Definitivamente no necesita inicializar unCar
objeto para inicializar unCar::Wheel
objeto en Ruby, pero laCar
clase debe cargarse y ejecutarse paraCar::Wheel
que se pueda usar.Car
yCar::Wheel
. Los módulos (y, por lo tanto, las clases) son simplemente espacios de nombres para constantes, no existe una clase anidada o un módulo anidado en Ruby.Car::Wheel.new
. Auge. Acabo de construir unWheel
objeto que no está anidado dentro de unCar
objeto.En Ruby, definir una clase anidada es similar a definir una clase en un módulo. En realidad, no fuerza una asociación entre las clases, solo crea un espacio de nombres para las constantes. (Los nombres de clase y módulo son constantes).
La respuesta aceptada no era correcta sobre nada. 1 En el ejemplo a continuación, creo una instancia de la clase encerrada léxicamente sin que exista una instancia de la clase encerradora.
Las ventajas son las mismas que para los módulos: encapsulación, agrupación de código utilizado en un solo lugar y colocación de código más cerca de donde se utiliza. Un proyecto grande puede tener un módulo externo que ocurre una y otra vez en cada archivo fuente y contiene muchas definiciones de clase. Cuando los diversos marcos y códigos de biblioteca hacen esto, solo contribuyen con un nombre al nivel superior, lo que reduce la posibilidad de conflictos. Prosaico, sin duda, pero es por eso que se usan.
El uso de una clase en lugar de un módulo para definir el espacio de nombres externo puede tener sentido en un programa o script de un archivo, o si ya usa la clase de nivel superior para algo, o si realmente va a agregar código para vincular las clases juntas en verdadera clase interna estilo de . Ruby no tiene clases internas, pero nada le impide crear el mismo comportamiento en el código. Hacer referencia a los objetos externos de los internos aún requerirá puntear desde la instancia del objeto externo, pero anidar las clases sugerirá que esto es lo que podría estar haciendo. Un programa cuidadosamente modularizado siempre puede crear primero las clases que lo encierran, y razonablemente se pueden descomponer con clases anidadas o internas. No puedes llamar
new
a un módulo.Puede usar el patrón general incluso para scripts, donde el espacio de nombres no es muy necesario, solo por diversión y práctica ...
fuente
B
está dentro de la clase . La constante tiene un espacio de nombres dentro de la clase , pero no hay absolutamente ninguna relación entre el objeto al que hace referencia (que en este caso es una clase) y la clase a la que hace referencia .A
B
A
B
A
You can't call new on a module.
así que, en términos básicos, si solo quiero crear espacios de nombres para algunas clases y nunca necesito crear una instancia de la "clase" externa, entonces Yo usaría un módulo externo. Pero si quiero crear una instancia de la "clase" envolvente / externa, la convertiría en una Clase en lugar de un Módulo. Al menos esto tiene sentido para mí.Probablemente quiera usar esto para agrupar sus clases en un módulo. Una especie de espacio de nombres.
por ejemplo, la gema de Twitter usa espacios de nombres para lograr esto:
Entonces, ambos
Client
y lasSearch
clases viven bajo elTwitter
módulo.Si desea verificar las fuentes, el código para ambas clases se puede encontrar aquí y aquí .
¡Espero que esto ayude!
fuente
Hay otra diferencia entre las clases anidadas y los módulos anidados en Ruby antes de 2.5 que otras respuestas no pudieron cubrir y creo que deben mencionarse aquí. Es el proceso de búsqueda.
En resumen: debido a la búsqueda constante de nivel superior en Ruby antes de 2.5, Ruby puede terminar buscando su clase anidada en el lugar incorrecto (
Object
en particular) si usa clases anidadas.En Ruby anterior a 2.5:
Estructura de clase anidada: suponga que tiene una clase
X
, con clase anidadaY
, oX::Y
. Y luego tienes una clase de nivel superior llamada tambiénY
. SiX::Y
no está cargado, entonces ocurre lo siguiente cuando se llamaX::Y
:Al no haber encontrado
Y
enX
, Ruby va a tratar de mirar hacia arriba en los antepasados deX
. Ya queX
es una clase y no un módulo, tiene ancestros, entre los cuales se encuentran[Object, Kernel, BasicObject]
. Entonces, trata de buscarY
adentroObject
, donde lo encuentra con éxito.Sin embargo, es el nivel superior
Y
y noX::Y
. Recibirá esta advertencia:Estructura de módulo anidado: suponga que en el ejemplo anterior
X
es un módulo y no una clase.Un módulo solo se tiene a sí mismo como ancestro:
X.ancestors
produciría[X]
.En este caso, Ruby no podrá buscar a
Y
uno de sus antepasadosX
y lanzará unNameError
. Los rieles (o cualquier otro marco con carga automática) intentarán cargarseX::Y
después de eso.Consulte este artículo para obtener más información: https://blog.jetbrains.com/ruby/2017/03/why-you-should-not-use-a-class-as-a-namespace-in-rails-applications/
In Ruby 2.5: Se
eliminó la búsqueda constante de nivel superior.
Puede usar clases anidadas sin temor a encontrar este error.
fuente
Además de las respuestas anteriores: Módulo en Ruby es una clase
fuente
new
. Entonces, aunque puede decir que los módulos son una clase (minúsculas), no son lo mismo que una clase (mayúsculas) :)