Подтвердить что ты не робот

Использование переменных экземпляра в методах класса - Ruby

У меня есть класс что-то вроде ниже, и я использовал переменные экземпляра (массив), чтобы избежать использования большого количества параметров метода.

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

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

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

Ответ 1

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

Так как 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 и вызвать его. Было бы нецелесообразно назначать переменные экземпляра здесь, потому что вы не сказали бы, что вызывающий контекст здесь (средство визуализации) содержит эту информацию в экземпляре. В самом рендерере нет "ссылки для ссылки", и, следовательно, он не должен быть похоронен в переменной экземпляра.

Ответ 2

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

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

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