如何在不影响超类的情况下覆盖Ruby子类中的变量?

时间:2013-10-15 13:34:09

标签: ruby

假设我有一个带有一些“静态”变量的类。我希望该类的子类能够覆盖这些变量而不会影响原始类。使用类变量是不可能的,因为它们似乎在子类和超类之间共享:

class Foo
  @@test = "a"

  def speak; puts @@test; end
end

class Bar < Foo
  @@test = "b"
end

Bar.new.speak
# b

Foo.new.speak
# b

使用常量也是不可能的:

class Foo
  TEST = "a"

  def speak; puts TEST; end
end

class Bar < Foo
  TEST = "b"
end

Bar.new.speak
# a

Foo.new.speak
# a

超类中定义的方法忽略子类中的常量。

明显的解决方法是为需要“可覆盖”的变量定义方法:

class Foo
  def test; "a"; end
end

但这感觉就像是黑客。我觉得这应该可以使用类变量,我可能只是做错了。例如,当我将Object子类化时(默认情况下会发生这种情况):

class Foo < Object
  @@bar = 123
end

Object.class_variable_get(:@@bar)
# NameError: uninitialized class variable @@bar in Object

为什么@@bar上的Object设置不像我上面的Bar < Foo示例中那样?


总结一下:如何在不影响超类的情况下覆盖子类中的变量?

3 个答案:

答案 0 :(得分:8)

类常量可以满足您的需求,您只需要以不同的方式使用它们:

class Foo
  TEST = "a"

  def speak
    puts self.class::TEST
  end
end

class Bar < Foo
  TEST = "b"
end

Bar.new.speak # => a
Foo.new.speak # => b

答案 1 :(得分:4)

向类本身添加一个变量(如在类实例中,而不是类变量):

class Foo
  @var = 'A'

  class << self
    attr_reader :var
  end

  def var
    self.class.var
  end
end

class Bar < Foo
  @var = 'B'
end

Foo.var # A
Foo.new.var # A
Bar.var # B
Bar.new.var # B

答案 2 :(得分:2)

正确的方法(恕我直言)是使用方法,因为这样你就可以按照自己的意愿使用继承和虚拟调度。

类变量在层次结构中共享,而不是向上共享。这就是为@@bar提供Object的原因。