Лучший способ сохранить коллекцию созданных объектов - PullRequest
2 голосов
/ 04 апреля 2011

Я хочу сохранить коллекцию созданных объектов Klass.Я имею в виду два метода:

Первый: через 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

Второй: через 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

Тестирование:

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

Оба работают, и я предпочитаю второй способ из-за «add»: он должен быть закрытым, и я должен использовать «Klass.send».Какой самый лучший способ?Есть ли какая-то другая (лучшая) манера?

Ответы [ 4 ]

3 голосов
/ 04 апреля 2011

Синусная инициализация вызывается каждый раз, когда создается новый объект, я бы воспользовался этим фактом и просто сделал бы:

def initialize *args
    # ... do regular initialization ...
    @@objs << self
end
1 голос
/ 04 апреля 2011

Обратите внимание, что ваши alias_method и private не были необходимы, поскольку new, который вы обычно вызываете, Class#new.Кроме того, нет причин использовать переменную класса (если вы не пытаетесь отслеживать создание подкласса в мастер-классе).Это работает так же хорошо, если не лучше:

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>]

Преимущество этого метода перед добавлением массива в вашем инициализаторе состоит в том, что вам не нужно помнить, чтобы вызывать super в * 1009.* ваших подклассов.В самом деле, вам не нужно даже определять и initialize в ваших подклассах.

1 голос
/ 04 апреля 2011

Не могли бы вы просто просто << в обычном конструкторе? Простой код, и вам не нужно переопределять new, что редко бывает хорошей идеей.

0 голосов
/ 05 апреля 2011

Вы также можете сделать

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
...