What is Replace Conditional with Polymorphism Refactoring? How is it implemented in Ruby?

后端 未结 2 927
清歌不尽
清歌不尽 2021-01-20 14:43

I recently came across the Replace Conditional with Polymorphism Refactoring while asking for elimination of if..else conditional in ruby.the l

2条回答
  •  青春惊慌失措
    2021-01-20 15:31

    The Replace Conditional with Polymorphism Refactoring is rather simple and it is pretty much exactly what it sounds like. You have a method with a conditional like this:

    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 the Refactoring again to NorwegianBlue#speed by creating a subclass of NorwegianBlue:

    class NorwegianBlue
      def speed
        base_speed(@voltage)
      end
    end
    
    class NailedNorwegianBlue < NorwegianBlue
      def speed
        0
      end
    end
    

    Voilà, all your conditionals are gone.

    You might ask yourself: does this always work? Can I always replace an if with message dispatch? And the answer is: yes, you can! In fact, if you didn't have if, you can implement it yourself using nothing but message dispatch. (This is, in fact, how Smalltalk does it, there are no conditionals 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: the Anti-IF Campaign

提交回复
热议问题