Eu sei que não há conceito de classe abstrata em rubi. Mas se for necessário implementá-lo, como proceder? Eu tentei algo como ...
class A
def self.new
raise 'Doh! You are trying to write Java in Ruby!'
end
end
class B < A
...
...
end
Mas quando tento instanciar B, ele vai chamar internamente, o A.new
que gerará a exceção.
Além disso, os módulos não podem ser instanciados, mas também não podem ser herdados. tornar o novo método privado também não funcionará. Alguma dica?
ruby
abstract-class
Chirantan
fonte
fonte
raise "Doh! You are trying to write Java in Ruby"
.Respostas:
Não gosto de usar classes abstratas em Ruby (quase sempre há uma maneira melhor). Se você realmente acha que é a melhor técnica para a situação, pode usar o seguinte snippet para ser mais declarativo sobre quais métodos são abstratos:
Basicamente, você apenas chama
abstract_methods
com a lista de métodos que são abstratos e, quando eles são chamados por uma instância da classe abstrata, umaNotImplementedError
exceção será gerada.fonte
NotImplementedError
que significa essencialmente "dependente da plataforma, não disponível no seu". Veja documentos .Apenas para adiar aqui tarde, acho que não há razão para impedir alguém de instanciar a classe abstrata, especialmente porque eles podem adicionar métodos rapidamente .
Linguagens de digitação de pato, como Ruby, usam a presença / ausência ou comportamento de métodos em tempo de execução para determinar se devem ser chamados ou não. Portanto, sua pergunta, como se aplica a um método abstrato , faz sentido
e isso deve ser sobre o fim da história. O único motivo para usar classes abstratas em Java é insistir que certos métodos sejam "preenchidos" enquanto outros têm seu comportamento na classe abstrata. Em uma linguagem de digitação de pato, o foco está nos métodos, não nas classes / tipos; portanto, você deve mover suas preocupações para esse nível.
Na sua pergunta, você está basicamente tentando recriar a
abstract
palavra-chave do Java, que é um cheiro de código para fazer Java no Ruby.fonte
Tente o seguinte:
fonte
#initialize
de B, você pode simplesmente aumentar o que for inicializado em A #if self.class == A
.fonte
para qualquer pessoa no mundo do Rails, a implementação de um modelo ActiveRecord como uma classe abstrata é feita com esta declaração no arquivo de modelo:
fonte
Meu 2 ¢: opto por uma mixagem DSL simples e leve:
E, é claro, adicionar outro erro para inicializar a classe base seria trivial nesse caso.
fonte
err = NotImplementedError.new(message); err.set_backtrace caller()
YMMVNos últimos 6 anos e meio de programação do Ruby, eu não precisei de uma aula abstrata nenhuma vez.
Se você pensa que precisa de uma aula abstrata, está pensando demais em uma linguagem que as forneça / exija, não no Ruby.
Como outros sugeriram, um mixin é mais apropriado para coisas que deveriam ser interfaces (como Java as define), e repensar seu design é mais apropriado para coisas que "precisam" de classes abstratas de outras linguagens como C ++.
Atualização 2019: não preciso de aulas abstratas em Ruby em 16 anos e meio de uso. Tudo o que todas as pessoas comentando sobre a minha resposta estão dizendo é abordado aprendendo Ruby e usando as ferramentas apropriadas, como módulos (que até oferecem implementações comuns). Existem pessoas nas equipes que eu gerenciei que criaram classes com implementação básica que falham (como uma classe abstrata), mas essas são principalmente um desperdício de codificação, porque
NoMethodError
produziriam exatamente o mesmo resultado queAbstractClassError
na produção.fonte
Você pode tentar 3 rubygems:
interface
resumo
simples resumo
fonte
Pessoalmente, levanto NotImplementedError em métodos de classes abstratas. Mas você pode deixar de fora o método 'novo', pelos motivos mencionados.
fonte
initialize
métodos não são chamados automaticamente, a menos que sejam explicitamente chamados com super.Se você deseja ir com uma classe instável, no seu método A.new, verifique se self == A antes de gerar o erro.
Mas, na verdade, um módulo parece mais com o que você deseja aqui - por exemplo, Enumerable é o tipo de coisa que pode ser uma classe abstrata em outros idiomas. Tecnicamente, você não pode subclassificá-los, mas chamar
include SomeModule
atinge aproximadamente o mesmo objetivo. Existe algum motivo para isso não funcionar para você?fonte
Qual o objetivo que você está tentando servir com uma classe abstrata? Provavelmente existe uma maneira melhor de fazê-lo em rubi, mas você não forneceu detalhes.
Meu ponteiro é esse; use um mixin não herança.
fonte
Outra resposta:
Isso depende do #method_missing normal para relatar métodos não implementados, mas evita a implementação de classes abstratas (mesmo se elas tiverem um método de inicialização)
Como os outros pôsteres disseram, você provavelmente deveria estar usando um mixin, em vez de uma aula abstrata.
fonte
Eu fiz dessa maneira, por isso redefine o novo na classe filho para encontrar um novo na classe não abstrata. Ainda não vejo nenhuma prática no uso de classes abstratas em ruby.
fonte
Há também essa pequena
abstract_type
jóia, que permite declarar classes e módulos abstratos de maneira discreta.Exemplo (do arquivo README.md ):
fonte
Nada de errado com sua abordagem. Gerar um erro na inicialização parece bom, desde que todas as suas subclasses substituam a inicialização, é claro. Mas você não quer se definir.novo assim. Aqui está o que eu faria.
Outra abordagem seria colocar toda essa funcionalidade em um módulo, que, como você mencionou, nunca pode ser instanciado. Em seguida, inclua o módulo em suas classes em vez de herdar de outra classe. No entanto, isso quebraria coisas como super.
Portanto, depende de como você deseja estruturá-lo. Embora os módulos pareçam uma solução mais limpa para solucionar o problema de "Como eu escrevo algumas coisas que são dignas para outras classes usarem"
fonte
Gema de 2 linhas: https://rubygems.org/gems/abstract
fonte
Embora isso não pareça Ruby, você pode fazer o seguinte:
Os resultados:
fonte