维护已创建对象集合的最佳方法

时间:2011-04-04 18:44:22

标签: ruby metaprogramming

我想维护一个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>]

两者都有效,我倾向于选择第二种方式,因为“添加”:它必须是私有的,我必须使用“Klass.send”。什么是最好的方法?还有其他(更好)的方式吗?

4 个答案:

答案 0 :(得分:3)

每次创建一个新对象时都会调用正弦初始化,我会利用这个事实并做到:

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

答案 1 :(得分:1)

你不能只是在普通构造函数中只是<<吗?简单的代码,您不必重新定义new这不是一个好主意。

答案 2 :(得分:1)

请注意,您不需要alias_methodprivate,因为您通常调用的newClass#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中调用initialize。实际上,您甚至不需要在子类中定义 initialize

答案 3 :(得分:0)

您也可以

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