12
votes

Comment modifier de manière dynamique l'héritage dans Ruby

Je voudrais spécifier de manière dynamique la classe mère pour une classe dans Ruby. Considérons ce code: xxx

ni le parent ni la définition de la classe de Spécifie une classe mère, de sorte qu'ils héritent tous les deux d'objet. Ma première question est la suivante: que devrais-je faire dans agent.hook_up afin de faire parent la superclasse de enfant (donc par exemple < Code> Enfant Les objets peuvent hériter de la méthode "bar").

Ma deuxième question est la suivante: Dois-je besoin pour transmettre le premier argument à Agent. harok_up ou existe une manière que la méthode harok_up peut déterminer par programme par programme à partir de laquelle il a été appelé?


3 commentaires

Si vous définissez ou changez de manière dynamique le parent d'une classe, c'est une affirmation raisonnable que votre modèle d'objet ne reflète pas une vraie relation une relation . Une solution plus appropriée est probablement la composition.


Vous devriez préciser si c'est un exercice de pensée, ou pourquoi vous voudriez utiliser cela dans la pratique. Les langages réfléchissants dynamiques ne veulent pas dire qu'il est propre pour changer de manière dynamique l'héritage. Avec un grand pouvoir (expressif), vient une grande responsabilité :)


@cletus Je ne suis pas un grand fan d'héritage en général mais pour le problème que je regarde actuellement, l'héritage et la relation est une relation parfaitement décrivant parfaitement la relation. Le seul problème est qu'un objet ne saura pas ce qu'il "est" jusqu'à ce que le temps d'exécution.


7 Réponses :


25
votes

Peut-être que vous recherchez ce xxx

puisque le parent est un argument de classe.Nouveau, vous pouvez l'échanger avec d'autres classes.

J'ai utilisé cette technique avant d'écrire certains types de tests. Mais j'ai du mal à penser à de nombreuses bonnes excuses pour faire une telle chose.


Je soupçonne ce que vous voulez vraiment est un module. xxx


Bien sûr, il n'y a pas besoin de l'agent du tout xxx


2 commentaires

Merci Joshua. Comme il semble que je ne puisse pas changer la chaîne d'héritage au moment de l'exécution, je finirai probablement à utiliser une variation de votre première option dans ma solution. J'apprécie le temps que vous avez réagi.


Une autre chose que vous pouvez regarder, si c'est vraiment ce que vous voulez faire, est Change_class écrit par Ryan Davis. Voici la vidéo où il introduit le code à 5:00 rubyconf2008.confreaks.com/evil-code .html Voici la page d'accueil du projet. Seatlerb.rubyforge.org/change_class Note la responsabilité "Oui, c'est dangereux ... Don ' t viens me pleurer si votre ordinateur s'allume. "



6
votes

Joshua vous a déjà donné une excellente liste d'alternatives, mais pour répondre à votre question: vous ne pouvez pas changer la superclasse d'une classe après la création de la classe dans Ruby. Ce n'est tout simplement pas possible.


2 commentaires

@Borromakot Statut du défi?


@Borromakot, sauf si vous remplissez leurs emplacements de mémoire :)



3
votes

Comme indiqué déjà, vous devez probablement regarder des modules ou créer de manière dynamique des cours. Cependant, vous pouvez utiliser Evil-Ruby pour changer la superclasse. Il y a même un Fourche pour Ruby 1.9 disponible. Cela ne fonctionne que pour l'IRM. Devrait être facile à construire sur Rubinius (méthodes de compensation des caches serait le problème principal), aucune idée de Jruby. Voici le code:

require 'evil'

class Agent
  def self.hook_up(calling_class, desired_parent_class)
    calling_class.superclass = desired_parent_class
  end
end

class Parent
  def bar
    puts "bar"
  end
end

class Child
  def foo
    puts "foo"
  end

  Agent.hook_up(self, Parent)
end

Child.new.bar


1 commentaires

Je suppose que l'utilisation du "mal" serait probablement fronçée dans le code de production :-) Créer de manière dynamique une classe est probablement la solution que je vais finir. Merci!



4
votes

Ruby 1.9 Seulement: (1,8 est similaire, mais utilisez rclass (auto) -> super à la place) xxx


0 commentaires

0
votes

SimpleDelegator classe (dans le délégué bibliothèque) peut aider, à condition que c'est suffisant que l'objet compensation comme em> la classe de base plutôt que soit une instance de em> la classe de base.

require 'delegate'

class Agent < SimpleDelegator
  def baz
    puts "baz"
  end
end

class BarParent
  def bar
    puts "bar"
  end
end

class FooParent
  def foo
    puts "foo"
  end
end

agent = Agent.new(FooParent.new)
agent.baz    # => baz
agent.foo    # => foo
agent.__setobj__(BarParent.new)
agent.baz    # => baz
agent.bar    # => bar


0 commentaires

0
votes

regarde sur ce xxx

et le sélecteur de classe: xxx

donc, lorsque l'instance myClass Sera hériter d'une classe dynamique en fonction de orm et modèle . Assurez-vous de définir les deux dans un module. Ça marche bien dans public_activité gem ( Exemple de sélecteur ).

J'espère aider .. Bye!


0 commentaires

0
votes

Je sais que cette question est assez ancienne et a déjà de bonnes réponses. Cependant, je manque toujours une solution certaine.

Si votre intention n'est pas d'attribuer de manière dynamique la superclasse, mais plutôt de créer un crochet pour exécuter du code sur héritage ( XY Problème ). Il y a une façon de faire cela. P>

Hérité (sous-classe) h3>

rappel invoqué chaque fois qu'une sous-classe de la classe actuelle est créée. P>

Exemple: P>

New subclass: Bar
New subclass: Baz


0 commentaires