2009-05-20 5 views
7

Je peux comprendre pourquoi vous auriez besoin d'une variable de classe pour garder une trace de choses comme le nombre total d'objets qui ont été instanciés dans cette classe.Avez-vous déjà utilisé une "variable d'instance de classe" dans votre code Ruby?

Et je peux comprendre pourquoi vous auriez besoin d'une variable d'instance pour stocker les attributs d'un objet particulier dans cette classe.

Mais variables d'instance de classe Je ne peux pas sembler justifier. Si je comprends bien, ils sont comme les variables de classe, sauf qu'ils sont non visibles aux sous-classes comme les variables de classe.

Il semble que les utilisations pour ce serait très limité. Ou ai-je tort? Quelqu'un at-il trouvé un bon usage des variables d'instance de classe dans leur code? Ou pourriez-vous donner un exemple d'une situation où ce type de nuance serait utile?

Répondre

4

que vous voulez compter le nombre d'instances d'une classe (non compris les sous-classes)

class A 
    @count = 0 
    @@count = 0 
    def self.inherited(subclass) 
    subclass.instance_eval { @count = 0 } 
    end 
    def self.num_instances 
    @count 
    end 
    def self.num_subclass_instances 
    @@count 
    end 
    def self.new 
    @count += 1 
    @@count += 1 
    super 
    end 
end 
class B < A 
end 
class C < B 
end 

A.new 
B.new 
A.new 
B.new 
B.new 
C.new 

A.num_instances #=> 2 
A.num_subclass_instances #=> 6 
B.num_instances #=> 3 
B.num_subclass_instances #=> 6 
C.num_instances #=> 1 
C.num_subclass_instances #=> 6 

Vous ne pouvez pas utiliser la variable de classe, puisque c'est partagé entre tous cours et ses sous-classes. Notez comment les modifications apportées à @@count par B et C sont reflétées dans A, mais @count n'est pas partagé.

En général, cependant, il peut être très utile pour stocker des paramètres spécifiques à la classe. _why l'utilise dans Dwemthy's Array pour spécifier des valeurs initiales pour les attributs d'instance, et cela revient souvent à faire de la métaprogrammation ruby.

+0

Merci. Grand exemple (s).Donc, fondamentalement, si nous avions seulement des variables de classe, nous ne serions pas capables de faire des choses comme ces comptes localisés pour A, B et C - nous serions coincés avec l'équivalent de vos num_subclass_instances. Je pense que je comprends maintenant. La seule partie de votre code que je n'ai pas comprise était: def self.inherited (subclass) subclass.instance_eval {@count = 0} end. Qu'est-ce que ça fait? –

+0

J'ai donc initialisé @count dans la définition de A, mais j'avais besoin d'initialiser @count à 0 pour toutes les sous-classes de A, ce que fait ce code. Lorsque A est hérité par 'subclass', nous ouvrons la sous-classe et initialisons son @count à 0. Essayez de supprimer cela, et vous verrez NoMethodErrors lorsque B et C sont instanciés, puisque Ruby ne saura pas comment ajouter 1 à zéro (la valeur par défaut de @count si elle n'est pas instanciée) – rampion

+0

Got it. Merci. En passant, je cherchais de la documentation sur instance_eval et l'ai trouvé pour 1.87 (http://www.rubybrain.com/api/ruby-1.8.7/doc/index.html?a=M000295&name=instance_eval) mais il semble comme c'est passé de 1,90 (http://www.rubybrain.com/api/ruby-1.9.0.2/doc/index.html?a=C00000022&name=Object). –

3

Les variables de classe sont partagées entre toutes les instances d'une classe, ce qui inclut toutes les sous-classes. Parfois, cette variable à travers une hiérarchie est exactement ce qui est nécessaire, mais parfois vous pourriez préférer une variable différente pour chaque classe. Contrairement aux variables de classe, les variables d'instance de classe prennent des valeurs différentes pour chaque objet de classe.

http://martinfowler.com/bliki/ClassInstanceVariable.html

3

Oui, en fait j'ai. Ceci est légèrement modifié et coupé de ce que j'avais:

class Widget 
    # class instance variable pattern 
    class << self; attr_accessor :color; end 

    def show_color() 
    "This widget is #{self.class.color}" 
    end 
end 
class WidgetR < Widget 
    @color = "Russet" 
end 
class WidgetC < Widget 
    @color = "Cordovan" 
end 
class WidgetL < Widget 
    @color = "Liver" 
end 

WidgetR.new.show_color #=> "This widget is Russet" 

Mais je ne suis pas sûr qu'il est vraiment nécessaire dans le cas je l'ai utilisé. J'aurais pu juste surcharger la méthode. Ou fourni une méthode de couleur. Ou stocké dans une variable de classe comme un hachage. Ou même gardé une copie dans chaque cas (ok, celui-ci est un peu yech). Je suis sûr qu'il existe d'autres possibilités ...

Il existe une variété d'alternatives et la syntaxe est maladroite. Étant donné que je devine les cas où c'est la chose la plus naturelle à utiliser sont probablement assez rares.

Il peut être utile de tenter de reproduire ce comportement avec des variables de classe et d'instance et de voir qu'il est difficile à réaliser (bien que cela soit facile si vous définissez des méthodes, etc.).

C.J.

Questions connexes