Ruby中的实例变量的通用setter?

时间:2018-05-07 23:26:26

标签: ruby eval

我在ruby中定义了一个Box类,它有3个实例变量:@ length,@ width,@ height和2个类变量:@@ boxcounter和@@ totalvolume。

虽然可以在对象构造函数(初始化程序)中更新@@ boxcounter的值,但更新@@ totalvolume的值变得不那么重要,因为每次我们更改任何一个时,我们都必须重新计算给定对象的体积实例变量(即长度,宽度或高度)。

我已经提出以下代码来处理这个用例:

class Box
  @@boxcounter = 0
  @@totalvolume = 0.0

  def initialize(length, width, height)
    @length = length
    @width = width
    @height = height
    @@boxcounter += 1
    @@totalvolume += volume
  end

  def volume
    volume = @length * @width * @height
  end

  def report
    puts "# of boxes: #{@@boxcounter}"
    puts "Total volume: #{@@totalvolume}"
    puts "Average volume per box: #{@@totalvolume / @@boxcounter}"
  end

  def my_print
    p self
    puts "Length: #{@length}"
    puts "Width: #{@width}"
    puts "Height: #{@height}"
    puts
  end

  def length=(length)
    @@totalvolume -= volume
    @length = length
    @@totalvolume += volume
  end

  def width=(width)
    @@totalvolume -= volume
    @width = width
    @@totalvolume += volume
  end

  def height=(height)
    @@totalvolume -= volume
    @height = height
    @@totalvolume += volume
  end
end

由于在学习Scheme之后,第一类对象的想法仍然存在,我想知道,我可以创建一个通用的setter并使用它来减少上面列出的每个setter中的代码重复吗?我试过这个,但使用eval似乎有点像黑客:

  def update_class_state(update_instance_variable)
    @@totalvolume -= volume
    eval update_instance_variable
    @@totalvolume += volume
  end

  def length=(length)
    update_class_state("@length = #{length}")
  end

  def width=(width)
    update_class_state("@width = #{width}")
  end

  def height=(height)
    update_class_state("@height = #{height}")
  end

- 我的问题:编写这样的代码是不好的做法?这种方法有更优雅的解决方案吗?

1 个答案:

答案 0 :(得分:1)

没有任何内在的错误"除了使用eval之外,您的方法。 这是一种更加动态的方式来删除重复而无需使用eval

class Box
  @@boxcounter = 0
  @@totalvolume = 0.0

  def initialize(length, width, height)
    @length = length
    @width = width
    @height = height
    @@boxcounter += 1
    @@totalvolume += volume
  end

  def volume
    volume = @length * @width * @height
  end

  def report
    puts "# of boxes: #{@@boxcounter}"
    puts "Total volume: #{@@totalvolume}"
    puts "Average volume per box: #{@@totalvolume / @@boxcounter}"
  end

  def my_print
    p self
    puts "Height: #{@height}"
  end

  # dynamically define your methods to dry up the code:
  %w[length width height].each do |method|
    define_method("#{method}=") do |arg|
      @@totalvolume -= volume
      instance_variable_set('@'+method, arg)
      @@totalvolume += volume
    end
  end
end