我常常发现自己的if / else语句与不同的值相比,基本上是重复的同一行。在这里,我编写代码来预测致命流感爆发造成的死亡人数。它已被重构为一个案例陈述,仍然非常WET:
def predicted_deaths(population_density, population, state)
case
when population_density >= 200 then number_of_deaths = (population * 0.4).floor
when population_density >= 150 then number_of_deaths = (population * 0.3).floor
when population_density >= 100 then number_of_deaths = (population * 0.2).floor
when population_density >= 50 then number_of_deaths = (population * 0.1).floor
else number_of_deaths = (population * 0.05).floor
end
ap "#{state} will lose #{number_of_deaths} people in this outbreak"
end
我尝试过使用
j = 0.4
i = 200
until i <= 50 do
@population_density >= i then number_of_deaths = (@population * j).floor
i -= 50
j -= 0.1
end
但那并没有真正做同样的事情。
如何让重复的个案陈述更干?
修改
这里有两个建议似乎是两个非常不同但同样好的重构:
为了便于阅读:
def predicted_deaths(population_density, population, state)
factor = case population_density
when 0...50 then 0.05
when 50...100 then 0.1
when 100...150 then 0.2
when 150...200 then 0.3
else 0.4
end
number_of_deaths = (population * factor).floor
ap "#{state} will lose #{number_of_deaths} people in this outbreak"
end
更浓缩但不太可读:
def predicted_deaths(population_density, population, state)
number_of_deaths = (population * 0.05).floor
for i in 1..4
number_of_deaths = (0.1 * i * population).floor if population_density.between?(50*i, 50*(i+1)) || population_density >= 200
end
ap "#{state} will lose #{number_of_deaths} people in this outbreak"
end
答案 0 :(得分:1)
考虑这个未经测试的代码:
def predicted_deaths(population_density, population, state)
pct = case
when population_density >= 200
0.4
when population_density >= 150
0.3
when population_density >= 100
0.2
when population_density >= 50
0.1
else
0.05
end
ap "#{state} will lose #{ (population * pct).floor } people in this outbreak"
end
我通过几个步骤来重构这样的代码,首先查找重复的部分并尝试将它们向下移出条件测试(这里的case
语句...呃。 ..案例)。
这是第一遍:
def predicted_deaths(population_density, population, state)
number_of_deaths = case
when @population_density >= 200
(@population * 0.4).floor
when @population_density >= 150
(@population * 0.3).floor
when @population_density >= 100
(@population * 0.2).floor
when @population_density >= 50
(@population * 0.1).floor
else
(@population * 0.05).floor
end
ap "#{@state} will lose #{number_of_deaths} people in this outbreak"
end
此时很明显@population *
和floor
是多余的,所以我把它们移了。
但是使用实例变量和局部变量时会出现问题。您引用了@population_density
,@population
和@state
,但在方法的参数中包含了用于传入值的局部变量。你不能这样做。删除@
以将变量转换为局部变量。
答案 1 :(得分:1)
一些事情:
1)您可以使case语句使用单个赋值:
state = case(city)
when "Miami" then "Florida"
when "Omaha" then "Nebraska"
...
end
2)你可以创建一个包含不常见逻辑的辅助函数(这将有助于显示不是DRY的东西):
def percentage_of_deaths_for_population_density(population_density)
case
when population_density >= 200 then 0.4
when population_density >= 150 then 0.3
when population_density >= 100 then 0.2
when population_density >= 50 then 0.1
else 0.05
end
然后您可以将代码段重写为:
def predicted_deaths(population_density, population, state)
number_of_deaths = (population * percentage_of_deaths_for_population_density(population_density)).floor
ap "#{state} will lose #{number_of_deaths} people in this outbreak"
end
3)最后如果你关心你可以进一步重构percentage_of_deaths_for_population
(但我认为它很可读并且可能会留下它 - 这真的只是你有一个巨大的陈述):
def percentage_of_deaths_for_population(population)
{ 200 => 0.4, 150 => 0.3, 100 => 0.2, 50 => 0.1 }.each do |limit, ratio|
return ratio if population >= limit
end
return 0.05
end
4)如果传入相同的变量,请不要使用实例变量!非常混乱。
答案 2 :(得分:1)
一种方法是缩短你的案例陈述:
def predicted_deaths(population_density, population, state)
factor = case population_density
when 0...50 then 0.05
when 50...100 then 0.1
when 100...150 then 0.2
when 150...200 then 0.3
else 0.4
end
number_of_deaths = (population * factor).floor
ap "#{state} will lose #{number_of_deaths} people in this outbreak"
end
答案 3 :(得分:0)
def predicted_death(population_density, population, state)
number_of_death = (@population * 0.05).floor
for i in 1..4
number_of_death = (0.1 * i * @population).floor if @population_density.between?(50*i, 50*(i+1)) || @population_density >= 200
end
ap "#{@state} will lose #{number_of_deaths} people in this outbreak"
end
答案 4 :(得分:0)
你可以用油煮沸,但我使用哈希而不是case
声明。
FACTORS_BY_DENSITY = { 200=>0.4, 150=>0.3, 100=>0.2, 50=>0.1, 0=>0.05 }
@data_by_state = {..., "Utah"=>{pop: 4_325_641, pop_density: 126 },...}
def predicted_deaths(state)
state_data = @data_by_state[state]
(state_data[:pop] * factor(state_data[:pop_density])).to_i
end
def factor(density)
FACTORS_BY_DENSITY.find { |d,_| density >= d }.pop
end
state = "Utah"
deaths = predicted_deaths(state)
#=> 865128
puts "#{state} will lose #{deaths} people in this outbreak"
# Utah will lose 865128 people in this outbreak