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

Класс << self vs self.method с Ruby: что лучше?

Этот Ruby Style Guide говорит, что лучше использовать self.method_name вместо class method_name. Но почему?

class TestClass
  # bad
  class << self
    def first_method
      # body omitted
    end

    def second_method_etc
      # body omitted
    end
  end

  # good
  def self.first_method
    # body omitted
  end

  def self.second_method_etc
    # body omitted
  end
end

Есть ли проблемы с производительностью?

4b9b3361

Ответ 1

class << self хорошо держит все ваши методы класса в одном блоке. Если методы добавляются в форме def self.method тогда нет никакой гарантии (кроме соглашения и желаемого мышления), что не будет дополнительного метода класса, спрятанного позже в файле.

def self.method хорошо в явном виде заявляет, что метод является методом класса, тогда как с class << self вы должны сами найти контейнер.

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

Ответ 2

Как правило, class << self используется в метапрограммировании, чтобы установить класс как "я" в течение длительного периода времени. Если я пытаюсь написать 10 методов, я бы использовал их так:

METHOD_APPENDICES = [1...10]
class << self
  METHOD_APPENDICES.each do |n|
    define_method("method#{n}") { n }
  end
end

Это создаст 10 методов (method1, method2, method3 и т.д.), которые просто вернут номер. Я использовал бы class << self для ясности в этом случае, потому что в метапрограммировании self имеет решающее значение. Засорение self. внутри там фактически сделает вещи менее читаемыми.

Если вы обычно определяете методы класса, придерживайтесь self.class_method_name, потому что больше людей, вероятно, это поймут. Не нужно вводить метасинтаксис, если вы не ожидаете, что ваша аудитория это поймет.

Ответ 3

Как отмечалось выше, оба стиля кажутся эквивалентными, однако использование class << self позволяет отмечать методы класса как private или protected. Например:

class UsingDefSelf
  def self.a; 'public class method'; end
  private
  def self.b; 'public class method!'; end
end

class UsingSingletonClass
  class << self
    def a; 'public class method'; end
    private
    def b; 'private class method'; end
  end
end

private влияет только на методы экземпляра. Используя класс singleton, мы определяем методы экземпляра этого класса, которые превращаются в методы класса содержащего класса!

Мы также можем пометить методы класса как private с помощью def self:

class UsingDefSelf
  def self.a; 'private class method'; end
  def self.b; 'private class method!'; end
  private_class_method :a, :b
  # In Ruby 2.1 there is an alternative syntax
  private_class_method def self.c; 'private class method!'; end
end

Но мы не можем отметить их как protected, нет protected_class_method. (Тем не менее, поскольку класс является единственным экземпляром его singletonclass, метод private class и методы защищенного класса почти одинаковы, но их синтаксис вызова отличается.)

Кроме того, менее удобно использовать class << self для обозначения методов класса private, так как вы должны перечислить все имена методов в private_class_method или префикс private_class_method для каждого определения метода частного класса.

Ответ 4

Я предполагаю, что они думают, что self.* лучше, потому что вы можете точно сказать, что это метод класса или экземпляра, не прокручивая и не используя эту строку class << self.

Ответ 5

Какой бы вы ни хотели. Оба очень понятны для того, что вы делаете. Но я думаю о некоторых рекомендациях для этого.

Если существует только один метод класса, Использовать def self.xxx. Потому что для определения только одного метода увеличение уровня отступа, вероятно, становится загромождать.

Если существует более одного метода класса, Использовать class << self. Поскольку запись def self.xxx, def self.yyy и def self.zzz, безусловно, повторяется. Создайте раздел для этих методов.

Когда все методы класса являются методами класса,, вы можете использовать module с module_function вместо class. Это позволяет вам определять функции модуля, просто используйте def xxx.

Ответ 6

Пока вопрос и ответы обсуждают только эти два варианта:

class MyClass
  def self.method_name
    ..
  end
end

class MyClass
  class << self
    def method_name
      ..
    end
  end
end

Но вот еще один вариант для рассмотрения методов класса/методов singleton/статических методов/методов, которые работают на уровне класса (или что бы вы еще не назовете их):

class MyClass
  def MyClass.method_name
    ..
  end
end

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

Я также пришел из фона Python, где self используется для методов экземпляра, тогда как в Ruby для методов класса используется self. Это часто меня смущает, поэтому, чтобы избежать мышления, "является ли метод self в Ruby методом класса или экземпляра?" Я использую def ClassName.methodname.