What replaces conditionally with polymorphism refactoring? How is this implemented in Ruby?
def speed
case @type
when :european then base_speed
when :african then base_speed - load_factor * @number_of_coconuts
when :norwegian_blue then if nailed? then 0 else base_speed(@voltage) end
end
and you replace it with polymorphism like this:
class European
def speed
base_speed
end
end
class African
def speed
base_speed - load_factor * @number_coconuts
end
end
class NorwegianBlue
def speed
if nailed? then 0 else base_speed(@voltage)
end
end
You can apply Refactoring to again by NorwegianBlue#speed
subclassing NorwegianBlue
:
class NorwegianBlue
def speed
base_speed(@voltage)
end
end
class NailedNorwegianBlue < NorwegianBlue
def speed
0
end
end
Voilà, all your conventions are gone.
You may be asking yourself: does this always work? Can I always replace a message if
with send messages? And the answer is yes you can ! In fact, if you didn't have one if
, you can implement it yourself using only posting. (This is essentially how Smalltalk does it; there is no convention in Smalltalk.)
class TrueClass
def iff(thn:, els: ->{})
thn.()
end
def &
yield
end
def |
self
end
def !
false
end
end
class FalseClass
def iff(thn:, els: ->{})
els.()
end
def &
self
end
def |
yield
end
def !
true
end
end
(3 > 4).iff(thn: ->{ 'three is bigger than four' }, els: ->{ 'four is bigger than three' } )
# => 'four is bigger than three'
true.& { puts 'Hello' }
# Hello
true.| { puts 'Hello' }
# => true
Also relevant: Anti- if
Campaign
source to share
I think I would format the highlighted phrase slightly differently, i.e.: Refactor your code to replace conditional polymorphism.
If this is indeed what this comment should mean, then Yehuda Katz has a great article giving an example in ruby: http://yehudakatz.com/2009/10/04/emulating-smalltalks-conditionals-in-ruby/
Basically, the argument is that there is an if / else statement to execute other code based on the boolean value. It requires special syntax and is limited to TrueClass / FalseClass types (or Object / NilClass if you're faint about truthfulness). Dynamic dispatch, on the other hand, performs the same operation of selecting branches of code to execute based on the value of an object, but does not rely on specialized syntax and is not limited to any particular group of types.
source to share