【问题标题】:How to refactor the below ruby code?如何重构下面的 ruby​​ 代码?
【发布时间】:2015-08-11 16:02:49
【问题描述】:

此代码由if/else 梯形图组成。它检查@tokens[0] 值并根据其内容调用函数:

if @tokens[0] == "add"
  @calculator.add(@tokens[1].to_f)
elsif @tokens[0] == "subtract"
  @calculator.subtract(@tokens[1].to_f)
elsif @tokens[0] == "multiply"
  @calculator.multiply(@tokens[1].to_f)
elsif @tokens[0] == "divide"
  @calculator.divide(@tokens[1].to_f)
elsif @tokens[0] == "sqr"
  @calculator.sqr
elsif @tokens[0] == "sqrt"
  @calculator.sqrt
elsif @tokens[0] == "cube"
  @calculator.cube
elsif @tokens[0] == "cubert"
  @calculator.cubert
end

我正在使用哈希映射来重构代码。除了 hashmap 之外,还有其他方法可以重构它吗?

【问题讨论】:

  • 有很多方法可以重构代码。你试过什么?您试图通过重构解决的问题/目标是什么?代码少?提高性能?更好的组织?更多的混淆?您的尝试是如何未能实现这些目标的?
  • @Chris 我对你的超能力很感兴趣;)
  • 您说您正在使用哈希映射,但是您的代码没有显示任何演示。 @tokens[0] 不是哈希访问器,除非您使用 0 作为键。相反,看起来您正在使用数组。请提供样本输入。照原样,有很多东西可以干燥。
  • @theTinMan :上面的代码显示了基本的 if/else 阶梯,我知道如何使用 hashmap 进行重构。我想让你知道任何其他重构它的方法
  • 如果您觉得其中任何一个有帮助,请不要忘记选择答案。

标签: ruby oop


【解决方案1】:

我尝试解读思想:

@calculator.public_send \
  case @tokens[0]
  when 'add', 'subtract', 'multiply', 'divide'
    @tokens[0], @tokens[1].to_f
  when 'sqr', 'sqrt', 'cube', 'cubert'
    @tokens[0]
  else fail 'Unsupported operation'
  end

【讨论】:

    【解决方案2】:

    类似这种未经测试的代码?

    action = @tokens[0].to_sym
    case action
    when :add, :subtract, :multiply, :divide
      @calculator.send(action, @tokens[1].to_f)
    else
      @calculator.send(action)
    end
    

    【讨论】:

    • 与我的回答相比有什么改进?
    • 可读性很重要。它也更简单。虽然您使用的是send,但用于收集参数的卷积是视觉噪声。
    • 而你的接受任何垃圾作为令牌,这显然与 OP 的意图相矛盾:)
    【解决方案3】:
    @calculator.send(@tokens[0],
      *case @tokens[0]
      when "add".freeze, "subtract".freeze, "multiply".freeze, "divide".freeze
        @tokens[1].to_f
      when "sqr".freeze, "sqrt".freeze, "cube".freeze, "cubert".freeze
        nil
      end
    )
    

    【讨论】:

    • 你能不能借助运行时多态性来实现它,比如把 add 作为一个类拉出来。
    【解决方案4】:

    你可以使用这样的东西

    have_param = ["add", "subtract", "multiply", "divide"]
    
    known_tokens = ["add", "subtract", "multiply", "divide", "sqr", "sqrt", "cube", "cubert"]
    
    t_0_value = @tokens[0]
    if known_tokens.include?(t_0_value)
      ( have_param.include?(t_0_value) ? @calculator.send(t_0_value, @tokens[1].to_f) : @calculator.send(t_0_value) )
    end
    

    【讨论】:

      【解决方案5】:

      有很多方法可以重构这个,这里是简单的:

      您可以使用看起来更简洁的 case 语句,如下所示:

      case @tokens[0]
      when "add" 
        @calculator.add(@tokens[1].to_f)
      when "subtract"
        @calculator.subtract(@tokens[1].to_f)
      when "multiply"
        @calculator.multiply(@tokens[1].to_f)
      when "divide"
        @calculator.divide(@tokens[1].to_f)
      when "sqr"
        @calculator.sqr
      when "sqrt"
        @calculator.sqrt
      when "cube"
        @calculator.cube
      when "cubert"
        @calculator.cubert
      end
      

      您可以将条件放在自己的哈希中:

      cases = { "add" => @calculator.add(@tokens[1].to_f),
      "subtract" => @calculator.subtract(@tokens[1].to_f),
      "multiply" => @calculator.multiply(@tokens[1].to_f),
      "divide" => @calculator.divide(@tokens[1].to_f),
      "sqr" => @calculator.sqr,
      "sqrt" => @calculator.sqrt,
      "cube" => @calculator.cube,
      "cubert" => @calculator.cubert }
      
      cases[@tokens[0]]
      

      你可以使用eval来调用函数,你不需要为每个操作都做一个case:

      case @tokens[0]
      when 'add', 'subtract', 'multiply', 'divide'
        eval("@calculator.#{@tokens[0]}(#{@tokens[1].to_f})")
      when 'sqr', 'sqrt', 'cube', 'cubert'
        eval("@calculator.#{@tokens[0]}")
      end
      

      这将调用函数并在令牌[0] 上使用 .to_f(如果它在数组中)

      @calculator.send(tokens[0], ['add', 'subtract', 'multiply', 'divide'].include? tokens[0] ? tokens[1].to_f : tokens[1])
      

      你可以把它放在@calculator 类中并且总是调用@calculator.calculate(tokens)

      def calculate(tokens)
          send(tokens[0], ['add', 'subtract', 'multiply', 'divide'].include? tokens[0] ? tokens[1].to_f : tokens[1])
      end
      

      【讨论】:

      • eval“解决方案”大笑。 不要那样做
      • 第二种解决方案(带哈希)显然评估了一切,例如由于divide 中抛出异常,不可能减去零。
      • @lassvi : 你能在运行时多态的帮助下实现吗,比如把 add 作为一个类拉出来。
      • 不确定你想做什么,如果你想让它全部由一个类完成,你可以将它添加为类中的一个自己的函数,我在我的答案中添加了一些代码,显示了一些例子。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多