Может ли класс в ruby ​​хранить количество экземпляров объектов, используя @class_instance_variable, а не @@class_variable?

Я пытаюсь вести подсчет экземпляров объектов данного класса внутри класса, который определяет эти объекты.

Прежде всего, я знаю об отражении кода и ObjectSpace.each_object, но я бы предпочел не использовать отражение и позволить самому классу "заботиться" о себе.

Я оглянулся вокруг, и все найденные решения, похоже, используют @@class_variables в определении класса, как, например, принятый ответ на этот вопрос: как получить экземпляры классов в Ruby?

Хотя я продолжал читать, я обнаружил, что переменные класса в ruby ​​могут вести себя очень плохо в некоторых ситуациях... главная причина заключается в следующем:

Переменная класса, определенная на верхнем уровне программы, наследуется всеми классами. Он ведет себя как глобальная переменная.

источник и дополнительная информация здесь: http://ruby.runpaint.org/variables

Итак, я попытался закодировать класс, который хранит количество своих экземпляров объектов внутри себя, используя переменную экземпляра класса вместо переменной класса, и, похоже, это работает нормально, но так как я все еще изучаю этот "углубленный" язык Темы, которые я хотел бы спросить, если код, который я написал, является правильным и / или имеет смысл:

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 мог рассчитывать только во время создания объекта и не иметь метода setter для своей переменной класса @instance, к которой можно обращаться в любое время в коде (Pizza.count = 1000). Вот почему я пытался переопределить "новый".

Я думаю, что это самая сложная часть, которая заставляет меня задаться вопросом, верен ли мой подход в правильном направлении, или если я просто должен прекратить так много полагаться на эти языковые механизмы и вместо этого добавить себе некоторую логику, чтобы подсчет происходил, только если объект класс Pizza вошел в ObjectSpace..

Я просто ищу более элегантный, не раздутый способ получить это, используя языковые функции.

В любом случае помощь будет оценена..

Еще раз спасибо.

2 ответа

Решение

Вам не нужно переопределять новое. Попробуй это:

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 в какой-то момент. (Не говорю, что это хорошая идея, но, например:

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

)

Вы правы. использование переменных класса несколько раз ошеломляет. я всегда забываю, если наследуется или нет и т. д.

ваш подход правильный, но...

НИКОГДА не переопределять new воплощать в жизнь initialize вместо! он будет вызван во время процесса инициализации каждого объекта. см. документы здесь: http://apidock.com/ruby/v1_9_3_125/Class/new

Другие вопросы по тегам