Eu estou bem familiarizado com quando usar subclasses e módulos, mas mais recentemente eu tenho visto classes aninhadas como esta:
class Foo
class Bar
# do some useful things
end
end
Bem como classes aninhadas em módulos como este:
module Baz
class Quux
# more code
end
end
A documentação e os artigos são escassos ou não sou educado sobre o assunto o suficiente para procurar os termos de pesquisa corretos, mas não consigo localizar muitas informações sobre o assunto.
Alguém poderia fornecer exemplos ou links para postagens sobre por que / quando essas técnicas seriam usadas?
Car.new
eCar::Wheel.new
. Definitivamente, você não precisa inicializar umCar
objeto para inicializá-loCar::Wheel
no Ruby, mas aCar
classe deve ser carregada e executada paraCar::Wheel
ser utilizável.Car
eCar::Wheel
. Módulos (e, portanto, classes) são simplesmente espaços de nomes para constantes; não existe classe ou módulo aninhado no Ruby.Car::Wheel.new
. Estrondo. Acabei de construir umWheel
objeto que não está aninhado dentro de umCar
objeto.Em Ruby, definir uma classe aninhada é semelhante a definir uma classe em um módulo. Na verdade, não força uma associação entre as classes, apenas cria um espaço para nomes para as constantes. (Os nomes de classe e módulo são constantes.)
A resposta aceita não estava correta sobre nada. 1 No exemplo abaixo, crio uma instância da classe fechada lexicamente sem que exista uma instância da classe envolvente.
As vantagens são as mesmas dos módulos: encapsulamento, código de agrupamento usado em apenas um lugar e colocação do código mais perto de onde é usado. Um projeto grande pode ter um módulo externo que ocorre repetidamente em cada arquivo de origem e contém muitas definições de classe. Quando as várias estruturas e códigos de biblioteca fazem isso, eles contribuem apenas com um nome para o nível superior, reduzindo a chance de conflitos. Prosaico, com certeza, mas é por isso que eles são usados.
O uso de uma classe em vez de um módulo para definir o espaço para nome externo pode fazer sentido em um programa ou script de um arquivo, ou se você já usa a classe de nível superior para alguma coisa ou se deseja adicionar código para vincular as classes no verdadeiro estilo da classe interna . Ruby não tem classes internas, mas nada impede que você crie o mesmo comportamento no código. A referência aos objetos externos a partir dos internos ainda exigirá pontos da instância do objeto externo, mas o aninhamento das classes sugerirá que é isso que você pode estar fazendo. Um programa cuidadosamente modularizado pode sempre criar primeiro as classes anexas e pode razoavelmente ser decompostas com classes internas ou aninhadas. Você não pode chamar
new
um módulo.Você pode usar o padrão geral mesmo para scripts, onde o espaço para nome não é muito necessário, apenas por diversão e prática ...
fonte
B
está dentro da classe . A constante está com namespace dentro da classe , mas não há absolutamente nenhum relacionamento entre o objeto referenciado por (que neste caso é uma classe) e a classe referenciada por .A
B
A
B
A
You can't call new on a module.
- portanto, em termos básicos, se eu apenas quiser nomear algumas classes e nunca precisar realmente criar uma instância da "classe" externa, Eu usaria um módulo externo. Mas se eu quiser instanciar uma instância da "classe" wrapping / outer, então eu a tornaria uma classe em vez de um módulo. Pelo menos isso faz sentido para mim.Você provavelmente deseja usar isso para agrupar suas classes em um módulo. Tipo de coisa de espaço para nome.
por exemplo, a gema do Twitter usa namespaces para conseguir isso:
Portanto, tanto as classes
Client
quanto asSearch
classes vivem sob oTwitter
módulo.Se você quiser verificar as fontes, o código para as duas classes pode ser encontrado aqui e aqui .
Espero que isto ajude!
fonte
Há ainda outra diferença entre as classes aninhadas e os módulos aninhados no Ruby anteriores à 2.5, que outras respostas falharam em abordar que considero que devem ser mencionadas aqui. É o processo de pesquisa.
Em resumo: devido à pesquisa constante de nível superior no Ruby anterior à 2.5, o Ruby pode acabar procurando sua classe aninhada no lugar errado (
Object
em particular) se você usar classes aninhadas.No Ruby anterior ao 2.5:
Estrutura de classe aninhada: suponha que você tenha uma classe
X
, com classe aninhadaY
, ouX::Y
. E então você tem uma classe de nível superior chamada tambémY
. SeX::Y
não estiver carregado, em seguida, seguindo acontece quando você chamaX::Y
:Não tendo encontrado
Y
emX
, Ruby vai tentar procurá-lo em antepassados deX
. Desde aX
é uma classe e não um módulo, possui ancestrais, entre os quais estão[Object, Kernel, BasicObject]
. Então, ele tenta procurarY
noObject
, onde encontra-lo com sucesso.No entanto, é o nível superior
Y
e nãoX::Y
. Você receberá este aviso:Estrutura do módulo aninhado: suponha que no exemplo anterior
X
seja um módulo e não uma classe.Um módulo tem apenas a si próprio como ancestral:
X.ancestors
produziria[X]
.Nesse caso, Ruby não poderá procurar
Y
em um dos ancestrais deX
e lançará aNameError
. O Rails (ou qualquer outra estrutura com carregamento automático) tentará carregarX::Y
depois disso.Consulte este artigo para obter mais informações: https://blog.jetbrains.com/ruby/2017/03/why-you-should-not-use-a-class-as-a-namespace-in-rails-applications/
Em Ruby 2.5:
Pesquisa constante de nível superior removida.
Você pode usar classes aninhadas sem medo de encontrar esse bug.
fonte
Além das respostas anteriores: Módulo em Ruby é uma classe
fonte
new
. Assim, embora você pode dizer Módulos são uma classe (em minúsculas), eles não são a mesma coisa que uma classe (maiúsculas) :)