5

我试图在定义这些对象的类中记录给定类的对象实例的计数。

首先,我知道代码反射和 ObjectSpace.each_object,但我不希望使用反射并让类本身能够“照顾”自己。

我环顾四周,我发现的所有解决方案似乎都在类定义中使用了@@class_variables,例如,这个问题的公认答案:如何在 Ruby 中获取类实例?

不过,当我不断阅读时,我发现 ruby​​ 中的类变量在某些情况下表现得非常糟糕……最大的原因是:

在程序顶层定义的类变量被所有类继承。它的行为就像一个全局变量。

来源和更多信息在这里:http ://ruby.runpaint.org/variables#class

因此,我尝试编写一个类,该类使用类实例变量而不是类变量将其实例化对象的数量存储在自身内部,显然它似乎工作正常,但因为我仍在学习这种“深入”语言我想问你我写的代码是否正确和/或有意义:

class Pizza
  @orders = 0
  def self.new
    @orders += 1
  end
  def self.total_orders
    @orders
  end
end

new_pizza = Pizza.new #=> 1
special_pizza = Pizza.new #=> 2
fav_pizza = Pizza.new #=> 3

我的一个疑问是,覆盖 Pizza.new 方法我“删除”了原始 .new 方法的一些重要功能?(原始的 .new 方法提供了什么?我如何使用反射“检查”方法代码?)我还做错了什么,或者我的方法完全错误,为什么?

谢谢

编辑:忘记添加这个重要的位:

作为一种更好地限制事物范围的方法,我希望 Pizza 类能够仅在对象实例化时进行计数,并且在其 @instance 类变量上没有 setter 方法,可以在代码中随时访问(Pizza.count = 1000)。这就是为什么我试图覆盖“新”。

我认为这是最棘手的部分,它让我问自己,我的方法是否朝着正确的方向前进,或者我是否应该停止过多依赖这些语言机制,而是给自己添加一些逻辑,让计数只有在Pizza 类已进入 ObjectSpace..

我只是在寻找更优雅、更不臃肿的方式来使用语言特性来获得它。

无论哪种情况,我们都将不胜感激..

再次感谢。

4

2 回答 2

9

您不需要覆盖新的。试试这个:

class Pizza
  @count = 0
  class << self
    attr_accessor :count
  end

  def initialize
    self.class.count += 1
  end
end

Pizza.new
Pizza.new
puts Pizza.count

请注意,Pizza.count当比萨被垃圾收集时它不会下降,当它们被收集时它不会上升dup

回答您的其他问题:我不确定您如何检查该new方法,但它可能是用 C 编写的,因此您应该查看 Ruby 源代码。我认为它基本上做到了这一点。

def new(*args, &block)
  o = allocate
  o.initialize(*args, &block)
  o
end

只要您super在某个时候调用,您就可以摆脱覆盖 new 的问题。(不是说这是一个好主意,而是例如:

class Foo
  def self.new
    # do whatever stuff you want here
    super
  end
end

)

于 2012-10-15T18:31:41.000 回答
1

你说的对。使用类变量有时令人难以置信。我总是忘记是否继承等。

你的方法是对的,但是...

永远不要覆盖new工具initialize!它会在每个对象的初始化过程中被调用。在此处查看文档:http: //apidock.com/ruby/v1_9_3_125/Class/new

于 2012-10-15T09:42:51.583 回答