DRY方式为对象分配函数值

时间:2014-08-08 12:09:04

标签: ruby dry

我有一个空对象,接受每个因子的计算值。该方法可读但长而丑。什么是DRY方式?

class ReadingScore

  def initialize(reading, score)
    @reading = reading
    @score = score
  end

  def assign_scoring_factors
    @score.heart_rate_factor              = heart_rate_factor
    @score.systolic_pressure_factor       = systolic_pressure_factor
    @score.diastolic_pressure_factor      = diastolic_pressure_factor
    @score.mean_pressure_factor           = mean_pressure_factor
    @score.signal_minimum_factor          = signal_minimum_factor
    @score.signal_average_factor          = signal_average_factor
    …
  end

  def heart_rate_factor
    @reading.heart_rate && (1..10).include?(@reading.heart_rate) ? 0 : 10
  end

  …
end

更新 本课程的总体目的是计算阅读的分数。我无法提供所有代码,因为它是医疗设备的专有算法。

但基本上有@reading n 因子被计算,然后保存到与@score相关联的@reading对象。因子的总和也计算为@score对象的总和。 @score对象如下所示:

  @score=
    #<Score:0x007faa0b33ec50
     @attributes=
      {"id"=>42,
       "reading_id"=>42,
       "sum_of_factors"=>10,
       "heart_rate_factor"=>10,
       "another_factor"=>0,
       "another_factor"=>0}

4 个答案:

答案 0 :(得分:2)

这似乎是目前为止最好的选择。问题的第一个答案开始于我这条路线,但海报似乎已经删除了它......

  def assign_factors_to_score
    factors.each do |factor|
      @score.public_send("#{factor}=", self.public_send(factor))
    end
  end

  def factors
    %i{factor_a factor_b factor_c factor_d}
  end

答案 1 :(得分:2)

您可以使用method_added自动填充一系列因子。这与你的答案中的因素的动态分配很好地结合在一起。

class ReadingScore
  @factors = []

  def self.method_added meth
    @factors << meth if meth =~ /_factor\Z/
  end

  def self.factors
    @factors
  end
end

请注意,这些是类方法,因此在实例方法中使用时需要使用self.class.factors

如果您没有看到如何集成此代码,

Here是一个完整的实现。

答案 2 :(得分:1)

您可以使用delegate

class ReadingScore
  extend Forwardable
  delegate [:heart_rate_factor=, :systolic_pressure_factor=,:diastolic_pressure_factor=,
      :mean_pressure_factor=,:signal_minimum_factor=,:signal_average_factor=] => :@score
  def initialize
    @score = Score.new
  end

  def assign_scoring_factors
    %w(heart_rate_factor systolic_pressure_factor diastolic_pressure_factor mean_pressure_factor signal_minimum_factor signal_average_factor).each do |meth|
      self.send("#{meth}=",self.send(meth))
    end
    self
  end
end

但我同意其他人的意见,重新考虑整个设计可能会更好。

您也可以使用tap,但代码看起来与您现在的代码非常相似。

此外,我不知道Score内部是什么样子,因为将此逻辑放在ScoreReading中并将所有这些传递给Score的方法或初始值设定项。 e.g。

class ReadingScore
   def intialize(reading)
     @reading = Reading.new(reading)
     @score = Score.new(@reading)
   end

end
class Reading
  #...
  def heart_rate_score
    heart_rate && (1..10).include?(@reading.heart_rate) ? 0 : 10
  end
  def systolic_pressure_score
    #logic
  end
  def diastolic_pressure_score
    #logic
  end
  def mean_pressure_score
    #logic
  end
  def signal_minimum_score
    #logic
  end
  def signal_average_score
    #logic
  end
end
class Score
  attr_accessor :heart_rate_factor,:systolic_pressure_factor,:diastolic_pressure_factor,
      :mean_pressure_factor,:signal_minimum_factor,:signal_average_factor
   def initialize(reading)
     factorialize(reading)
     self
   end


  private
    def factorialize(reading)
      %w(heart_rate systolic_pressure diastolic_pressure mean_pressure signal_minimum signal_average) do |meth|
        self.send("#{meth}_factor=",reading.send("#{meth}_score")
      end
    end
 end

这样,您的逻辑就集中在ScoreReading中,可以在ReadingScore中避免使用。这将使代码更容易跟踪,并将清理原始类。

答案 3 :(得分:-1)

如果你坚持的话,你可以这样做:

def assign_scoring_factors
  %w(heart_rate systolic_pressure diastolic_pressure mean_pressure signal_minimum signal_average).each |f| do
    eval("@score.#{f}.factor = #{f}.factor")
  end
end

但这不是我要做的。我要么保持湿润,要么只是使用地图。