Класс << 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
Есть ли проблемы с производительностью?
Ответы
Ответ 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
.