处理许多 if 条件的更好方法?

Better way to handle many if conditions?

我们有许多不同类型的提要。一个提要有很多 feed_comments。根据提要类型,我想 return 一个特定的字符串。

if feed.type == 1
  if nested_comment
    str = "test"
  else if comment
    str = "test1"
  else
    str = "test2"
  end 
else if feed.type == 2
  if nested_comment
    str = "test3"
  else if comment
    str = "test4"
  else
    str = "test5"
  end 
else if feed.type == 3
  if nested_comment
    str = "test6"
  else if comment
    str = "test7"
  else
    str = "test8"
  end 
else if feed.type == 4
  if nested_comment
    str = "test9"
  else if comment
    str = "test10"
  else
    str = "test11"
  end 
end

编写上面代码的更好方法是什么,这样如果我们有更多的条件,我以后就不必更改现有代码了?

要获得更易于管理和可读的代码,您可以尝试 case statements。除此之外,我看不出你还能如何压缩代码,因为正如有人指出的那样,每种可能性都有不同的结果。

case feed.type
when 1
  case
  when nested_comment then str = "test"
  when comment        then str = "test2"
  else                     str = "test3"
  end
when 2
  case
  when nested_comment then str = "test"
  when comment        then str = "test2"
  else                     str = "test3"
  end
 # repeat for each feed number type
end
results = {
  1 => {
    nested_comment: 'test1',
    comment: 'test2',
    else: 'test3'
  }
}

comment_type = nested_comment ? :nested_comment : comment ? :comment : :else
results[feed.type][comment_type]

此代码可以极大地受益于Replace Conditional with Polymorphism Refactoring

一般来说,您从不在面向对象语言中根本不需要任何条件,因为面向对象语言具有运行时多态消息调度,这比任何条件都更强大.你可以总是用多态替换条件; Smalltalk 是这方面的存在证明,它甚至 没有 语言中的条件,它们是使用消息调度在库中实现的,有点像这样:

class TrueClass
  def if_then_else(then_part, else_part)
    then_part.()
  end
end

class FalseClass
  def if_then_else(then_part, else_part)
    else_part.()
  end
end

(2 < 3).if_then_else(-> { puts 'True' }, -> { puts 'False' })
# True

Ruby 有条件句,但你不需要它们。

那么,运行时多态消息分派到底做了什么?好吧,它基本上根据类型执行不同的代码。例如,如果您说

foo.bar

不同的 bar 方法将 运行 基于 foo 的类型。

在您的情况下,您用来决定执行哪个代码的值 字面意思 称为 type,因此,您本质上是只是重新实现 Ruby 的一个基本功能:根据类型执行不同的代码 只是消息分发,Ruby 无论如何它自己完成。

因此,在您的情况下,您将有 4 个不同的 Feed 类 和 2 个不同的 Comment 类.

现在,就您而言,情况稍微复杂一些,因为结果不仅仅取决于提要类型,还取决于评论类型。 Ruby 没有多重调度,因此,我们要么需要为提要类型和评论类型的每种组合引入新的 类,要么在最终代码中使用一些条件。

所以,让我们开始慢慢改进您的代码。首先,我相信你的意思是 elsif 而不是 else if 在你的代码中:

if feed.type == 1
  if nested_comment
    str = "test"
  elsif comment
    str = "test1"
  else
    str = "test2"
  end 
elsif feed.type == 2
  if nested_comment
    str = "test3"
  elsif comment
    str = "test4"
  else
    str = "test5"
  end 
elsif feed.type == 3
  if nested_comment
    str = "test6"
  elsif comment
    str = "test7"
  else
    str = "test8"
  end 
elsif feed.type == 4
  if nested_comment
    str = "test9"
  elsif comment
    str = "test10"
  else
    str = "test11"
  end 
end

其次,我们可以利用Ruby中的条件是表达式,而不是语句(实际上,Ruby中的所有内容都是表达式,没有语句),因此评估值:

str = if feed.type == 1
  if nested_comment
    "test"
  elsif comment
    "test1"
  else
    "test2"
  end 
elsif feed.type == 2
  if nested_comment
    "test3"
  elsif comment
    "test4"
  else
    "test5"
  end 
elsif feed.type == 3
  if nested_comment
    "test6"
  elsif comment
    "test7"
  else
    "test8"
  end 
elsif feed.type == 4
  if nested_comment
    "test9"
  elsif comment
    "test10"
  else
    "test11"
  end 
end

现在,我们将 if 替换为 case 表达式:

str = case feed.type
when 1
  case
  when nested_comment
    "test"
  when comment
    "test1"
  else
    "test2"
  end 
when 2
  case
  when nested_comment
    "test3"
  when comment
    "test4"
  else
    "test5"
  end 
when 3
  case
  when nested_comment
    "test6"
  when comment
    "test7"
  else
    "test8"
  end 
when 4
  case
  when nested_comment
    "test9"
  when comment
    "test10"
  else
    "test11"
  end 
end

现在,让我们重新格式化一下,以便更容易地看到发生了什么:

str = case feed.type
when 1
  case
  when nested_comment then "test"
  when comment        then "test1"
  else                     "test2"
  end 
when 2
  case
  when nested_comment then "test3"
  when comment        then "test4"
  else                     "test5"
  end 
when 3
  case
  when nested_comment then "test6"
  when comment        then "test7"
  else                     "test8"
  end 
when 4
  case
  when nested_comment then "test9"
  when comment        then "test10"
  else                     "test11"
  end 
end

是时候进行重构了:

class Feed1
  def magic_string
    case
    when nested_comment then "test"
    when comment        then "test1"
    else                     "test2"
    end
  end
end

class Feed2
  def magic_string
    case
    when nested_comment then "test3"
    when comment        then "test4"
    else                     "test5"
    end
  end
end

class Feed3
  def magic_string
    case
    when nested_comment then "test6"
    when comment        then "test7"
    else                     "test8"
    end
  end
end

class Feed4
  def magic_string
    case
    when nested_comment then "test9"
    when comment        then "test10"
    else                     "test11"
    end
  end 
end

str = feed.magic_string

我们可以通过引入一种封装评论检查的方法来进一步减少一些重复(或者,就像我说的,我们可以引入评论类)。

class Feed
  def comment_string(nested_comment_string, comment_string, other_string)
    case
    when nested_comment then nested_comment_string
    when comment        then comment_string
    else                     other_string
    end
  end
end

class Feed1 < Feed
  def magic_string
    comment_string("test", "test1", "test2")
  end
end

class Feed2 < Feed
  def magic_string
    comment_string("test3", "test4", "test5")
  end
end

class Feed3 < Feed
  def magic_string
    comment_string("test6", "test7", "test8")
  end
end

class Feed4 < Feed
  def magic_string
    comment_string("test9", "test10", "test11")
  end 
end

str = feed.magic_string