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 endcan 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:Fixnumwhich 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_childthere 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 endBoth 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