Использование переменных экземпляра в методах класса - Ruby - PullRequest
48 голосов
/ 16 февраля 2012

Я очень плохо знаком с ruby ​​(я на самом деле c # dev.), Так что этот вопрос может быть нубским.У меня есть класс что-то вроде ниже, и я использовал переменные экземпляра (массив), чтобы избежать использования большого количества параметров метода.

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

class DummyClass
  def self.dummy_method1
    @arr = []
    # Play with that array
  end

  def self.dummy_method2
    # use @arr for something else
  end
end

Ответы [ 2 ]

67 голосов
/ 16 февраля 2012

Причина, по которой переменные экземпляра работают с классами в Ruby, заключается в том, что классы Ruby сами являются экземплярами (экземплярами класса Class ).Попробуйте сами, проверив DummyClass.class.В Ruby не существует «статических методов» в смысле C #, потому что каждый метод определен (или унаследован) в некотором экземпляре и вызван в некотором экземпляре.Соответственно, они могут получить доступ к любым переменным экземпляра, которые могут быть доступны в вызываемом объекте.

Поскольку DummyClass является экземпляром, он может просто иметь свои собственные переменные экземпляра.Вы даже можете получить доступ к этим переменным экземпляра, если у вас есть ссылка на класс (что должно быть всегда, потому что имена классов являются константами).В любой момент вы сможете вызвать ::DummyClass.instance_variable_get(:@arr) и получить текущее значение этой переменной экземпляра.

Что касается того, стоит ли это делать, это зависит от методов .

Если @arr логически является «состоянием» экземпляра / класса DummyClass, сохраните его в переменной экземпляра.Если @arr используется только в dummy_method2 в качестве рабочего ярлыка, передайте его в качестве аргумента.Чтобы привести пример, где используется подход с использованием переменной экземпляра, рассмотрим ActiveRecord в Rails.Это позволяет вам сделать это:

u = User.new
u.name = "foobar"
u.save

Здесь имя, которое было назначено пользователю, является данными, которые законно принадлежат пользователю.Если перед вызовом #save кто-то спросит «как зовут пользователя в данный момент», вы ответите «foobar».Если вы углубитесь во внутренние ресурсы (вы будете копаться очень глубоко и в метапрограммировании, вы обнаружите, что они используют переменные экземпляра именно для этого).

Пример, который я использовал, содержит дваотдельные публичные призывы.Чтобы увидеть случай, когда переменные экземпляра все еще используются, несмотря на то, что выполняется только один вызов, посмотрите на реализацию ActiveRecord #update_attributes.Тело метода просто load(attributes, false) && save.Почему #save не передаются никакие аргументы (например, новый name), даже если он находится в теле сохранения где-то вроде UPDATE users SET name='foobar' WHERE id=1;?Это потому, что такие вещи, как имя, являются информацией, которая принадлежит экземпляру.

И наоборот, мы можем рассмотреть случай, когда переменные экземпляра не имеют смысла использовать.Посмотрите на реализацию #link_to_if, метод, который принимает аргумент boolean-ish (обычно это выражение в исходном коде) наряду с аргументами, которые обычно принимаются #link_to, такими как URL для ссылки на,Когда логическое условие истинно, ему необходимо передать остальные аргументы в #link_to и вызвать его.Не имеет смысла назначать здесь переменные экземпляра, потому что вы не сказали бы, что вызывающий контекст здесь (средство визуализации) содержит эту информацию в экземпляре.Само средство визуализации не имеет «URL-адреса для ссылки», и, следовательно, его не следует скрывать в переменной экземпляра.

21 голосов
/ 16 февраля 2012

Это переменные экземпляра класса, и они вполне допустимы в ruby: классы тоже являются объектами (экземплярами класса) и поэтому имеют переменные экземпляра.

Следует обратить внимание на то, что каждый подкласс будет иметьсвой собственный набор переменных экземпляра класса (в конце концов, это разные объекты): если вы вложите в подкласс DummyClass, методы класса в подклассе не смогут видеть @arr.

переменных класса (@@foo), конечно, наоборот: вся иерархия классов использует одни и те же переменные класса.

...