Je sais qu'il n'y a pas de concept de classe abstraite en rubis. Mais s'il faut le mettre en œuvre, comment s'y prendre? J'ai essayé quelque chose comme ...
class A
def self.new
raise 'Doh! You are trying to write Java in Ruby!'
end
end
class B < A
...
...
end
Mais quand j'essaye d'instancier B, il appelle en interne A.new
ce qui va lever l'exception.
De plus, les modules ne peuvent pas être instanciés mais ils ne peuvent pas non plus être hérités. rendre la nouvelle méthode privée ne fonctionnera pas non plus. Des pointeurs?
ruby
abstract-class
Chirantan
la source
la source
raise "Doh! You are trying to write Java in Ruby"
.Réponses:
Je n'aime pas utiliser des classes abstraites dans Ruby (il y a presque toujours une meilleure façon). Si vous pensez vraiment que c'est la meilleure technique pour la situation, vous pouvez utiliser l'extrait de code suivant pour être plus déclaratif sur les méthodes abstraites:
Fondamentalement, vous appelez simplement
abstract_methods
avec la liste des méthodes abstraites, et lorsqu'elles sont appelées par une instance de la classe abstraite, uneNotImplementedError
exception sera déclenchée .la source
NotImplementedError
qui signifie essentiellement "dépendant de la plate-forme, non disponible sur le vôtre". Voir la documentation .Juste pour marquer tard ici, je pense qu'il n'y a aucune raison d'empêcher quelqu'un d'instancier la classe abstraite, surtout parce qu'ils peuvent y ajouter des méthodes à la volée .
Les langages de typage Duck, comme Ruby, utilisent la présence / absence ou le comportement des méthodes au moment de l'exécution pour déterminer si elles doivent être appelées ou non. Par conséquent, votre question, telle qu'elle s'applique à une méthode abstraite , a du sens
et cela devrait être la fin de l'histoire. La seule raison d'utiliser des classes abstraites en Java est d'insister pour que certaines méthodes soient "remplies" tandis que d'autres ont leur comportement dans la classe abstraite. Dans un langage de typage canard, l'accent est mis sur les méthodes, pas sur les classes / types, vous devriez donc déplacer vos inquiétudes à ce niveau.
Dans votre question, vous essayez essentiellement de recréer le
abstract
mot - clé à partir de Java, qui est une odeur de code pour faire Java dans Ruby.la source
Essaye ça:
la source
#initialize
de B, vous pouvez en fait simplement lever n'importe quoi dans A # initializeif self.class == A
.la source
pour quiconque dans le monde des rails, l'implémentation d'un modèle ActiveRecord en tant que classe abstraite se fait avec cette déclaration dans le fichier de modèle:
la source
Mon 2 ¢: j'opte pour un mixin DSL simple et léger:
Et, bien sûr, ajouter une autre erreur pour initialiser la classe de base serait trivial dans ce cas.
la source
err = NotImplementedError.new(message); err.set_backtrace caller()
YMMVAu cours des 6 1/2 dernières années de programmation de Ruby, je n'ai pas eu besoin d' une classe abstraite une seule fois.
Si vous pensez avoir besoin d'une classe abstraite, vous pensez trop dans un langage qui les fournit / les exige, pas dans Ruby en tant que tel.
Comme d'autres l'ont suggéré, un mixin est plus approprié pour les choses qui sont supposées être des interfaces (comme Java les définit), et repenser votre conception est plus appropriée pour les choses qui "nécessitent" des classes abstraites d'autres langages comme C ++.
Mise à jour 2019: je n'ai pas eu besoin de classes abstraites dans Ruby depuis 16 ans et demi d'utilisation. Tout ce que disent toutes les personnes qui commentent ma réponse est abordé en apprenant réellement Ruby et en utilisant les outils appropriés, comme des modules (qui vous donnent même des implémentations courantes). Il y a des gens dans les équipes que j'ai dirigées qui ont créé des classes dont l'implémentation de base échoue (comme une classe abstraite), mais ce sont surtout un gaspillage de codage car
NoMethodError
cela produirait exactement le même résultat qu'uneAbstractClassError
en production.la source
Vous pouvez essayer 3 rubygems:
interface
abstract
simple abstract
la source
Personnellement, je lève NotImplementedError dans les méthodes de classes abstraites. Mais vous voudrez peut-être la laisser en dehors de la «nouvelle» méthode, pour les raisons que vous avez mentionnées.
la source
initialize
méthodes des parents ne sont pas appelées automatiquement à moins qu'elles ne soient explicitement appelées avec super.Si vous voulez utiliser une classe non instable, dans votre méthode A.new, vérifiez si self == A avant de lancer l'erreur.
Mais en réalité, un module ressemble plus à ce que vous voulez ici - par exemple, Enumerable est le genre de chose qui pourrait être une classe abstraite dans d'autres langages. Vous ne pouvez pas techniquement les sous-classer, mais appeler
include SomeModule
atteint à peu près le même objectif. Y a-t-il une raison pour laquelle cela ne fonctionnera pas pour vous?la source
Quel but essayez-vous de servir avec une classe abstraite? Il y a probablement une meilleure façon de le faire en rubis, mais vous n'avez donné aucun détail.
Mon pointeur est le suivant; utiliser un mixin pas un héritage.
la source
Une autre réponse:
Cela s'appuie sur le #method_missing normal pour signaler les méthodes non implémentées, mais empêche les classes abstraites d'être implémentées (même si elles ont une méthode d'initialisation)
Comme les autres affiches l'ont dit, vous devriez probablement utiliser un mixin plutôt qu'une classe abstraite.
la source
Je l'ai fait de cette façon, donc cela redéfinit la nouvelle classe enfant pour trouver une nouvelle classe non abstraite. Je ne vois toujours pas de pratique à utiliser des classes abstraites dans ruby.
la source
Il y a aussi ce petit
abstract_type
bijou, qui permet de déclarer des classes et des modules abstraits de manière discrète.Exemple (à partir du fichier README.md ):
la source
Rien de mal avec votre approche. Générer une erreur lors de l'initialisation semble correct, tant que toutes vos sous-classes écrasent bien sûr initialize. Mais vous ne voulez pas définir self.new comme ça. Voici ce que je ferais.
Une autre approche consisterait à mettre toutes ces fonctionnalités dans un module, qui, comme vous l'avez mentionné, ne peut jamais être instauré. Incluez ensuite le module dans vos classes plutôt que d'hériter d'une autre classe. Cependant, cela casserait des choses comme super.
Cela dépend donc de la manière dont vous souhaitez le structurer. Bien que les modules semblent être une solution plus propre pour résoudre le problème de "Comment écrire des trucs daignés pour d'autres classes à utiliser"
la source
Gemme de 2 lignes: https://rubygems.org/gems/abstract
la source
Bien que cela ne ressemble pas à Ruby, vous pouvez le faire:
Les resultats:
la source