Не так давно, занявшись изучением ruby, я столкнулся с тем, что не понимаю, что такое class методы, точнее в чем их отличие от instance и зачем они вообще нужны. В учебнике, который я изучаю на данный момент, эта тема была описана не достаточно подробно или я не дочитал до подробного описания, но в любом случае мне стало интересно разобраться и я полез искать ответы в google. Данный пост является всем тем, что мне удалось найти и понять. Конечно, для опытных ruby разработчиков тут интересного мало, но я надеюсь, что смогу помочь таким же новичкам в языке как и я. Если я вас заинтриговал — прошу под кат.
Для начала, давайте определимся: в ruby все объекты. Это нужно впитать, усвоить и всегда помнить. Даже классы — это объекты имя которых — константа. И с каждым объектом можно совершать какие либо действия благодаря методам. Следовательно, возникает резонный вопрос: можно ли что-то делать с классами благодаря методам?
Думаю, что многие догадаются, что ответ на этот вопрос будет положительный, даже больше скажу: в ruby каждый метод является либо методом экземпляра (instance method) либо методом класса (class method соответственно). Отличаются они, кроме способа создания, только тем, что первые методы вызываются с экземпляром класса, а вторые — с классом. Важно понимать, в чем заключается различие между этими двумя методами и уметь определять когда и какой метод использовать. Поэтому рассмотрим методы класса (class methood), но для начала напомню, а может для кого и расскажу, что такое методы экземпляра.
Часто используемые, обычно с таких методов начинается изучение языка практически во всех учебниках. Обычно создаются они тремя способами:
Ничего сложного и все понятно. Используются они везде и всюду. Например: в rails модули экземпляра могут отвечать за создание и удаление тех же постов, ну или часто встречающийся метод — метод сложения.
Руби очень гибкий и лаконичный язык, поэтому он предоставляет нам аж целых четыре различных способа создания методов класса:
Собственно создание данных методов тоже не представляет сложностей. Все представленные способы одинаково работают и единственное что их различает — вкус разработчика. В первом и во втором способе используется одна и та же конструкция, с единственным различием в переменной
Когда стоит пользоваться данными методами? Обычно их используют, когда вы имеете дело не с отдельными экземплярами класса. Самый банальный пример — методы валидации в rails. Выглядит код примерно так:
К этому примеру можно так же отнести все методы
Бывают случаи, когда в методе класса необходимо вызвать метод экземпляра, ruby для этих целей предоставляет элегантный способ:
А иногда бывают случаи когда наоборот, нужно вызвать метод класса в методе экземпляра. Для этих целей нужно использовать метод
Важно понимать, что
P.S.: Спасибо товарищу walkman7 за то, что помог найти ошибку в последнем примере.
Для начала, давайте определимся: в ruby все объекты. Это нужно впитать, усвоить и всегда помнить. Даже классы — это объекты имя которых — константа. И с каждым объектом можно совершать какие либо действия благодаря методам. Следовательно, возникает резонный вопрос: можно ли что-то делать с классами благодаря методам?
Думаю, что многие догадаются, что ответ на этот вопрос будет положительный, даже больше скажу: в ruby каждый метод является либо методом экземпляра (instance method) либо методом класса (class method соответственно). Отличаются они, кроме способа создания, только тем, что первые методы вызываются с экземпляром класса, а вторые — с классом. Важно понимать, в чем заключается различие между этими двумя методами и уметь определять когда и какой метод использовать. Поэтому рассмотрим методы класса (class methood), но для начала напомню, а может для кого и расскажу, что такое методы экземпляра.
Методы экземпляра (instance metods):
Часто используемые, обычно с таких методов начинается изучение языка практически во всех учебниках. Обычно создаются они тремя способами:
# Способ 1 class Test def foo puts 'Метод экземпляра' end end a = Test.new a.foo # => "Метод экземпляра" # Способ 2 class Test attr_accessor :foo end a = Test.new a.foo = 'Метод экземпляра' puts a.foo # Способ 3 class Test; end a = Test.new def a.foo puts 'Метод экземпляра' end Test.new.foo # => "Метод экземпляра"
Ничего сложного и все понятно. Используются они везде и всюду. Например: в rails модули экземпляра могут отвечать за создание и удаление тех же постов, ну или часто встречающийся метод — метод сложения.
Методы класса (class methods):
Руби очень гибкий и лаконичный язык, поэтому он предоставляет нам аж целых четыре различных способа создания методов класса:
# Способ 1 class Test def self.foo puts 'Метод класса' end end Test.foo # => "Метод класса" # Способ 1 class Test def Test.foo puts 'Метод класса' end end Test.foo # => "Метод класса" # Способ 3 class Test class << self def foo puts 'Метод класса' end end end Test.foo # => "Метод класса" # Способ 4 class Test; end def Test.foo puts 'Метод класса' end Test.bar # => "Метод класса"
Собственно создание данных методов тоже не представляет сложностей. Все представленные способы одинаково работают и единственное что их различает — вкус разработчика. В первом и во втором способе используется одна и та же конструкция, с единственным различием в переменной
self. Третий случай интересен тем, что создается анонимный класс, а последний — очень похож на создание синглтона. Когда я вижу код, похожий на self.name_class_method, я понимаю, что это метод класса, поэтому я соглашаюсь со мнением людей, утверждающих, что в первом случае код более читаемый, так как он создает меньше путаницы. Когда стоит пользоваться данными методами? Обычно их используют, когда вы имеете дело не с отдельными экземплярами класса. Самый банальный пример — методы валидации в rails. Выглядит код примерно так:
module ActiveRecord class Base def self.validates_of(...) # Код валидации end end end class Foo < ActiveRecord::Base validates_of :bar # не посредственное использование метода в классе end
К этому примеру можно так же отнести все методы
arrt_* семейства. Так же, есть замечательный метод new, который содержат в себе все экземпляры класса Class.Взаимодействие instance и class методов между собой.
Бывают случаи, когда в методе класса необходимо вызвать метод экземпляра, ruby для этих целей предоставляет элегантный способ:
# Использование instance метода в class методе. class Test def instance_method # код метода end def self.class_method a = Test.new a.instance_method end end
А иногда бывают случаи когда наоборот, нужно вызвать метод класса в методе экземпляра. Для этих целей нужно использовать метод
class:# Использование class метода в instance методе. class Test def self.class_method puts self end def instance_method self.class.class_method end end
Важно понимать, что
self возвращает значение конкретного класса, поэтому иногда происходит путаница, когда нужно, что бы и наследники такого класса возвращали метод родителя. Для этих целей нужно использовать вместо self непосредственно имя класса родителя:class Test1 def self.class_method "foo" end def make1 self.class.class_method end def make2 Test1.class_method end end class Test2 < Test1 def self.class_method "abc" end end b = Test2.new b.make1 # => "abc" b.make2 # => "foo"
P.S.: Спасибо товарищу walkman7 за то, что помог найти ошибку в последнем примере.
