- PVSM.RU - https://www.pvsm.ru -

Class методы в ruby

Не так давно, занявшись изучением ruby, я столкнулся с тем, что не понимаю, что такое class методы, точнее в чем их отличие от instance и зачем они вообще нужны. В учебнике, который я изучаю на данный момент, эта тема была описана не достаточно подробно или я не дочитал до подробного описания, но в любом случае мне стало интересно разобраться и я полез искать ответы в google. Данный пост является всем тем, что мне удалось найти и понять. Конечно, для опытных ruby разработчиков тут интересного мало, но я надеюсь, что смогу помочь таким же новичкам в языке как и я. Если я вас заинтриговал — прошу под кат.

Для начала, давайте определимся: в 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.default_make
    "abc"
  end
end

b = Test2.new 
b.make1 # => "abc" 
b.make2 # => "foo" 

Автор: Fikys

Источник [1]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/ruby/32169

Ссылки в тексте:

[1] Источник: http://habrahabr.ru/post/176763/