Статьи

Руководство по сцеплению методов

method_chaining

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

Возможно, вы уже так или иначе взаимодействовали с цепочкой методов, особенно если вы использовали ActiveRecord. Помните, что вы делали что-то вроде этого Model.where(…).order(…) Да, это метод цепочки. В этой статье вы узнаете, как применять те же функции в своем собственном коде.

Эта статья будет разделена на две простые части:

  • Введение в метод цепочки
  • Метод цепочки на уровне класса

Первая часть будет охватывать основы цепочки методов, с пошаговыми примерами; а во второй части будет объяснено, как выполнить цепочку методов на уровне класса, будь то с помощью явного объявления метода методов класса или с помощью и расширения дополнительного модуля.

Вы готовы отправиться в это удивительное путешествие? Пошли!

Введение в метод цепочки

Для вводной части мы собираемся разработать класс, который будет содержать несколько методов, которые в конечном итоге могут быть объединены в цепочку, и один метод, который выводит сообщение. Давайте начнем с нашей базовой структуры классов:

 class Person

  def name(value)
  end

  def age(value)
  end

  def introduce
  end

end

Ничего особенного, но это послужит основой для этого примера. Как видите, он содержит три метода: name() age() introduce Имея эту основную информацию под рукой, давайте осуществим следующий шаг.

Теперь мы собираемся сохранить входные значения для name()age()

 # ...
def name(value)
  @name = value
end

def age(value)
  @age = value
end
# ...

Отлично, с этим дополнением к нашим методам, давайте попробуем цепочку методов и посмотрим, что произойдет:

 > person = Person.new
# => #<Person:0x007fb18ba29cb8>
> person.name('Baz')
# => "Baz"
> person.name('Baz').age(21)
NoMethodError: undefined method `age' for "Baz":String

Как и следовало ожидать, это не работает. Причина в том, что методы просто возвращают значение — в данном случае строку. Нам нужно изменить наши методы еще раз, и на этот раз мы собираемся вернуть что-то еще: self

Возвращая self Полегче, да ?! Хорошо, пришло время снова изменить наши методы:

 # ...
def name(value)
  @name = value
  self
end

def age(value)
  @age = value
  self
end
# ...

Фантастика, что произойдет, если мы попытаемся связать наши вызовы методов?

 > person = Person.new
# => #<Person:0x007ff202829e38>
> person.name('Baz')
# => #<Person:0x007ff202829e38 @name="Baz">
> person.name('Baz').age(21)
# => #<Person:0x007ff202829e38 @name="Baz", @age=21>

Это сработало! Поздравляем, вы только что внедрили цепочку методов в Ruby! Теперь нам нужно изменить наш метод introduce

 # ...
def introduce
  puts "Hello, my name is #{@name}, and I am #{@age} years old."
end
# ...

Как вы думаете, что произойдет, когда весь наш код будет на месте, когда мы вызовем introduce

 > person = Person.new
# => #<Person:0x007fd079085ba0>
> person.name('Baz').age(21).introduce
# => Hello, my name is Baz and I am 21 years old.

Да, это сработало, как и ожидалось. Обратите внимание, что метод introduceself

Вот полный код для этого примера, который я также внес в Википедию в статье, посвященной методам :

 class Person

  def name(value)
    @name = value
    self
  end

  def age(value)
    @age = value
    self
  end

  def introduce
    puts "Hello, my name is #{@name} and I am #{@age} years old."
  end

end

В качестве упражнения для читателя я призываю вас изменить метод introduce Например, если доступен только @name Если доступен только @age

Цепочка методов на уровне класса

Мы только что узнали, как связывать вызовы наших методов при вызове методов для экземпляра класса. Но как насчет объединения методов на уровне класса, аналогично Model.where(…).order(…) Это почти тот же процесс, за исключением того, что объявление нашего метода будет на уровне класса, а не на уровне экземпляра.

Давайте продолжим и сделаем это, давайте разработаем класс, который содержит методы класса, которые могут быть объединены в цепочку. Базовая структура для этого примера будет выглядеть примерно так:

 class Speaker
  class << self

    def say(what)
      @say = what
      self
    end

    def drink(what)
      @drink = what
      self
    end

    def output
      "The speaker drinks #{@drink} and says #{@say}"
    end

  end
end

Довольно просто, правда? Обратите внимание, что все эти три метода являются методами класса. Я мог бы объявить их по отдельности с помощью def self.say()…class << self

Отлично, давайте поиграем с этим сейчас:

 > Speaker.say('hello').drink('water').output
# => The speaker drinks water and says hello

И вот он у вас, работал как шарм.

Еще один способ сделать это без явного объявления методов класса — использовать модуль и extend Делая это, мы выставляем методы в модуле как методы класса в нашем классе Speaker

 module SpeakerClassMethods
  def say(what)
    @say = what
    self
  end

  def drink(what)
    @drink = what
    self
  end

  def output
    "The speaker drinks #{@drink} and says #{@say}"
  end
end

class Speaker
  extend SpeakerClassMethods
end

И он должен работать точно так же, как явно объявив методы класса:

 > Speaker.say('hello').drink('water').output
# => The speaker drinks water and says hello

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

Вывод

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