The benefits are:
- less intermediate variables (and therefore more readable)
- predictable results (and therefore a stable API)
class Person
def initialize name, gender
@name = name
@gender = gender
end
def marries person
@marriage_partner = person
end
def bear_child
return unless @gender.eql? 'f'
@children ||= 0
@children += 1
end
end
can create a new person, who can marry another person and even bear children, if its gender is female. The class can be used like:
@alice = Person.new 'Alice', 'f' @bob = Person.new 'Bob', 'm' @alice.bear_child @alice.marries @bobThe code can be refactored by method chaining into one single line:
Person.new('Alice', 'f').bear_child.marries(Person.new('Bob', 'm'))
=> NoMethodError: undefined method `marries' for 1:Fixnum
which fails, because the method bear_child returns a number (1) and not the expected Person object.If the order of the chaining is changed:
Person.new('Alice', 'f').marries(Person.new('Bob', 'm')).bear_child
there is no exception, but it is still an unexpected result. It is even worse, because the bug is harder to debug. The reason is: in the example the method marries returns @bob, who obviously can not bear a child.Well, methods can only be chained perfectly, if they return something meaningful and predictable.
The refactored Person class in person.rb:
class Person
def initialize name, gender
@name = name
@gender = gender
end
def marries person
@marriage_partner = person
self
end
def bear_child
return self unless @gender.eql? 'f'
@children ||= 0
@children += 1
self
end
end
Both methods marries and bear_child return self in every case. So that they can be chained together in a cascading style like:
Person.new('Alice', 'f').bear_child.marries(Person.new('Bob', 'm'))
=> #<Person:0x00000001be31f0 @name="Alice", @gender="f", @marriage_partner=#<Person:0x00000001be30b0 @name="Bob", @gender="m">, @children=1>
and it does not matter in which order:
Person.new('Alice', 'f').marries(Person.new('Bob', 'm')).bear_child
=> #<Person:0x00000001be31f0 @name="Alice", @gender="f", @marriage_partner=#<Person:0x00000001be30b0 @name="Bob", @gender="m">, @children=1>
the interim result is always the same expected person and the result state is equal.Please note, that the meaning of nil is pretty low and even true and false are only meaningful in certain contexts.
Supported by Ruby 2.1.1
Keine Kommentare:
Kommentar veröffentlichen