【问题标题】:How to refactor nested case statements (in this case)?如何重构嵌套的 case 语句(在这种情况下)?
【发布时间】:2012-12-19 22:07:21
【问题描述】:

我正在使用 Ruby on Rails 3.2.9 和 Ruby 1.9.3。我有以下case 声明:

case
when private?
  case
  when not_active? then [:a, :b, :c, :d]
  when active?     then raise "private cannot be active"
  else raise "not recognized"
  end
when shared?
  case
  when not_active? then [:a, :b, :c]
  when active?     then raise "shared cannot be active"
  else raise "not recognized"
  end
when public?
  case
  when not_active? then [:a, :b]
  when active?     then [:a]
  else raise "not recognized"
  end
else raise "not recognized"
end

如何重构上述代码?

【问题讨论】:

  • @Andrew Marshall - 我不明白您为什么(至少)删除了 ruby-on-rails 标记,因为可能有一些 RoR 方法可以帮助重构问题中发布的代码.
  • 您能详细解释一下active?not_active? 方法吗?它们是互补的吗,我的意思是not_active? == !active? 是这样吗?
  • 你的代码怎么能转到raise "not recognized"
  • @Khaled - 是的,它们是互补的(not_active? == !active?# => true)。
  • @oldergod - 你可能是对的,因为方法是互补的。

标签: ruby-on-rails ruby refactoring switch-statement


【解决方案1】:
raise "not recognized" unless private? or shared? or public?
raise "not recognized" unless not_active? or active?
raise "private cannot be active" if private? and active?
raise "shared cannot be active" if shared? and active?

[:a, *(:b unless active?), *(:c unless public?), *(:d if private?)]


通过更改错误消息,您可以使其更加舒适:
raise "visibility not recognized" unless private? or shared? or public?
raise "activeness not recognized" unless not_active? or active?
raise "active must be public" if active? and not public?

[:a, *(:b unless active?), *(:c unless public?), *(:d if private?)]

顺便说一下,inactive? 是一个比 not_active? 更好的方法名称。

【讨论】:

    【解决方案2】:

    一个有组织的:

    CONDITIONS = 
      {"private?" => {"not_active?" => [:a, :b, :c, :d],
                      "active?"     => "private cannot be active"},
      {"shared?"  => {"not_active?" => [:a, :b, :c],
                      "active?"     => "shared cannot be active"},
      {"public?"  => {"not_active?" => [:a, :b],
                      "active?"     => [:a]}}
    
    def foo(it)
      value = "not recognised"
      CONDITIONS.each do |k, v|
        if it.send(k.to_sym)
          v.each do |inner_k, inner_v|
            if it.send(inner_k.to_sym)
              value = inner_v
            end
          end
        end
      end
    
      raise value if (value.class.name == "String")
    
      value
    end
    

    在扩展的情况下,你只需要使 CONDITIONS 散列更大。

    【讨论】:

    • 您的方法似乎使事情变得“复杂”而不是“促进”它们,主要是在条件(即嵌套case 语句时)数量增加时。
    • 那你还没有完全指定任务。 :) 无论如何,然后对值使用多级哈希。
    • 您的意思是什么以及如何使用“值的多级散列”?
    • 是的,但是(再次 :-( )它似乎有“复杂”的东西,而不是“促进”它们。
    • 需求似乎和它一样复杂。然而,只要你只使用布尔函数来区分,这个解决方案就可以工作,并且尽可能干净。如果这还不够好,那么我现在帮不了你。也许首先尝试根据决定以某种方式计算单个索引,并将其应用于简单的哈希。但是我已经晚了,我做不到。 :)
    【解决方案3】:

    干燥的恋物癖:

    class Public
      def not_active; [:a, :b]; end
      def active; not_active.first; end
      def missing_method; false; end
    end
    
    class Shared < Public
      def not_active; super << :c; end
      def active; raise "#{self.class.name.underscore} cannot be active"; end
    end
    
    class Private < Shared
      def not_active; super << :d; end
    end
    
    state = active? ? :active : (not_active? ? :not_active : :missing_method)
    (Private.new.send(state) if private?)||
    (Shared.new.send(state) if shared?)||
    (Public.new.send(state) if public?)||raise("not recognized")
    

    【讨论】:

      【解决方案4】:

      使用数组怎么样?

      actions = [
          ['[:a, :b, :c, :d]', 'raise "private cannot be active"'],
          ['[:a, :b, :c]', 'raise "shared cannot be active"'],
          ['[:a, :b]', '[:a]']
      ]
      
      x = [:private?, :shared?, :public?].find_index { |i| send(i) }
      y = [:not_active?, :active?].find_index { |i| send(i) }
      
      if x and y
          eval(actions[x][y])
      else
          raise "not recognized"
      end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-09
        • 1970-01-01
        • 2021-07-03
        相关资源
        最近更新 更多