2015-05-14 2 views
1

Я пытаюсь понять себя в Ruby.Понимание себя с помощью метода chaining

В коде вставили ниже, если я создаю новый экземпляр животных с

fox = Animal.new.name("Fox").color("red").natural_habitat("forest").specie("mammal")

, а затем вызвать

fox.to_s

Это ничего не делать, если я не вернусь самостоятельно в каждом методе.

Зачем мне нужно самостоятельно в каждом методе? Является ли переменная уже сохраненной после создания нового Animal?

class Animal 
    def name(name) 
    @name = name 
    self 
    end 
    def specie(specie) 
    @specie = specie 
    self 
    end 
    def color(color) 
    @color = color 
    self 
    end 
    def natural_habitat(natural_habitat) 
    @natural_habitat = natural_habitat 
    self 
    end 
    def to_s 
    "Name: #{@name}, Specie: #{@specie}, Color: #{@color}, Natural Habitat: #{@natural_habitat}" 
    end 
    end 
+2

Если вы хотите иметь прикованные методы/свободный интерфейс, вам нужно вернуть объект из каждого вызова метода.В противном случае вы не можете вызвать дополнительные методы для результата вызова метода. – deceze

ответ

3

Этот шаблон используется нечасто в Ruby, он гораздо чаще встречается в таких языках, как Java и JavaScript, где он особенно распространен в jQuery. Часть причины, почему вы здесь описываете, и, во-вторых, поскольку Ruby предоставляет удобный генератор мутаторов в виде attr_accessor или attr_writer.

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

def color(*color) 
    case (color.length) 
    when 1 
    @color = color 
    self 
    when 0 
    @color 
    else 
    raise ArgumentError, "wrong number of arguments (%d for 0)" % color.length 
    end 
end 

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

animal.color('red') 
animal_color = animal.color 

Если вы хотите использовать их, Вы должны будете написать ваш собственный метапрограммный метод, который может их генерировать, хотя я бы очень не поощрял этот путь в первую очередь. Используйте методы attr_accessor и варианты Хэш.

Вот эквивалент модель Ruby:

# Up-front assignment via Hash 
animal = Animal.new(
    name: 'Fox', 
    color: 'red', 
    natural_habitat: 'forest', 
    specie: 'mammal' 
) 

# Assignment after the fact 
animal.color = 'white' 
1

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

fox = Animal.new 
fox.name("Fox").color("red").natural_habitat("forest").specie("mammal") 

Значение fox.name("Fox") является сам экземпляр, поэтому вы можете позвонить .color("red") на него.

+0

@mudasobwa Я не говорю, что он возвращает новый экземпляр, я говорю, что он возвращает сам экземпляр, т. Е. Сам 'fox' в этом примере. –

1

если метод #name будет реализован без вызова себя, например, так:

def name(name) 
    @name = name 
end 

Этот метод возвращает строку при вызове.

Animal.new.name #=> returns "name of animal" 

Это означает, что

Animal.new.name.specie 

бы вызвать метод #specie на строковый объект (который, вероятно, повышает ошибку NotImplemented) вместо объекта класса Animal, который реализует метод.

Смежные вопросы