我们有许多不同类型的Feed。一个Feed有很多feed_comments
。根据Feed类型,我想返回一个特定的字符串。
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
如果我们有更多条件,编写上述代码的更好方法是什么,以便将来不必更改现有代码?
答案 0 :(得分:4)
要获得更易于管理和可读的代码,您可以尝试使用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
答案 1 :(得分:3)
此代码可以从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
类。
现在,在您的情况下,它有点复杂,因为结果不仅取决于Feed类型,还取决于评论类型。 Ruby没有多个调度,所以,我们要么需要为feed类型和注释类型的每个组合引入新类,要么在最终代码中使用一些条件。
因此,让我们开始慢慢改进您的代码。首先,我相信您的代码中的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
答案 2 :(得分:1)
results = {
1 => {
nested_comment: 'test1',
comment: 'test2',
else: 'test3'
}
}
comment_type = nested_comment ? :nested_comment : comment ? :comment : :else
results[feed.type][comment_type]