2011-04-04 2 views
2

Je souhaite gérer une collection d'objets créés d'un Klass. J'ai deux méthodes d'esprit im:Meilleure façon de gérer une collection d'objets créés

Première: Thru initialize:

class Klass 
    @@objs = [] 

    def initialize *args 
    # ... do regular initialization ... 
    Klass.send :add, self 
    end 

    class << self 
    def objs 
     @@objs 
    end 

    private 

    def add obj 
     @@objs << obj 
    end 
    end 
end 

Deuxième: Thru new:

class Klass 
    @@objs = [] 

    class << self 
    def objs 
     @@objs 
    end 

    alias_method :old_new, :new # never thought someday I'd name something as "old_new"! 
    private :old_new 

    def new *args 
     obj = super 
     @@objs << obj 
     obj 
    end 
    end 
end 

Test:

a = Klass.new 
b = Klass.new 
puts a.inspect   #=> #<Klass:0xb7786ba0> 
puts b.inspect   #=> #<Klass:0xb7786b78> 
puts Klass.objs.inspect #=> [#<Klass:0xb7786ba0>, #<Klass:0xb7786b78>] 

Les deux ouvrages, et je tends de préférer la deuxième façon, à cause de "ajouter": il doit être privé, et je dois utiliser "Klass.send" . Quel est le meilleur moyen? Y a-t-il une autre (meilleure) manière?

Répondre

1

Pourriez-vous simplement simplement << dans le constructeur normal? Code simple et vous n'avez pas à redéfinir new ce qui est rarement une bonne idée.

+0

Merci! J'étais aveugle! –

3

initialize Sine est appelé à chaque fois qu'un nouvel objet est créé, je profiterais de ce fait et il suffit de faire:

def initialize *args 
    # ... do regular initialization ... 
    @@objs << self 
end 
+0

Jakub a dit essentiellement la même chose. Merci quand même! :) –

1

Notez que votre alias_method et private n'étaient pas nécessaires, comme new vous appelez normalement est Class#new. En outre, il n'y a aucune raison d'utiliser une variable de classe (sauf si vous essayez de suivre les créations de sous-classe sur la classe principale). Cela fonctionne aussi bien, sinon mieux:

class Foo 
    class << self; attr_reader :objs; end 
    def self.new(*a,&b) 
    super.tap{|o| (@objs||=[]) << o} 
    end 
end 
class Bar < Foo; end 
2.times{ Foo.new } 
3.times{ Bar.new } 

p Foo.objs 
#=> [#<Foo:0x2bb6260>, #<Foo:0x2ba2400>] 

p Bar.objs 
#=> [#<Bar:0x2ce6000>, #<Bar:0x2baf4e0>, #<Bar:0x2b94f40>] 

L'avantage de cette technique par rapport au tableau annexant dans votre initialiseur est que vous n'avez pas besoin de se rappeler d'appeler super dans le initialize de vos sous-classes. En effet, vous n'avez même pas besoin de pour définir et initialize dans vos sous-classes.

+0

+1 pour ouvrir les yeux sur 'Class # new' et pour utiliser' tap' (super! Si je connaissais 'tap' avant, je l'utiliserais dans mon deuxième exemple). Mais '' '' dans 'initialize' (et l'utilisation de variables de classe) est ce que je cherchais. Je connais les variables d'instances de classe et leurs avantages par rapport aux variables de classe, mais dans ce cas, j'utiliserai des variables de classe. –

+0

@SonySantos Pas de problème, et je suis content que vous ayez la réponse que vous cherchiez. J'ai ajouté cette réponse (vu que vous aviez déjà accepté une réponse) non parce que j'essayais de vous influencer pour passer à ma réponse, mais seulement pour que d'autres utilisateurs avec des besoins légèrement différents trouvant cette question aient une autre réponse à considérer. Codage Happy Ruby! :) – Phrogz

+0

J'ai réalisé que mon intention initiale était de faire 'obj = old_new * args' au lieu de' obj = super' dans mon deuxième exemple. Je ne sais pas pourquoi cela a fonctionné. Si j'appelle 'super' depuis l'intérieur d'une méthode d'instance, il enverra un message d'une classe parente de l'objet en cours - ie,' object.class.superclass' - pour exécuter une méthode d'instance avec le même nom. Si j'appelle 'super' d'une méthode de classe, je suppose qu'il enverra un message d'une classe parente de la classe courante en tant qu'instance, c'est-à-dire,' Klass.class.superclass', qui est 'Module', qui n'a pas' new' comme méthode d'instance. –

0

Vous pouvez également faire

class IndividualKlass 
end 

class KlassCreator 
    def initialize(individual_klass) 
    @individual_klass = individual_klass 
    @objects = [] 
    end 

    def create_object 
    object = @individual_klass.new 
    @objects << object 
    object 
    end 
end 

klass_creator = KlassCreator.new(IndividualKlass) 
IndividualKlass = nil # Or remove_const or something 

object = klass_creator.create_object 
+0

Très intéressant! :) –

Questions connexes