让父类的方法访问子类的常量

时间:2012-01-26 06:48:11

标签: ruby constants

例如:

class Animal

 def make_noise
    print NOISE
 end

end

class Dog < Animal
    NOISE = "bark"
end

d = Dog.new
d.make_noise # I want this to print "bark" 

如何完成上述操作?目前它说

uninitialized constant Animal::NOISE

5 个答案:

答案 0 :(得分:27)

我认为你真的不想要一个常数;我认为你想在类上有一个实例变量:

class Animal
  @noise = "whaargarble"
  class << self
    attr_accessor :noise
  end
  def make_noise
    puts self.class.noise
  end
end

class Dog < Animal
  @noise = "bark"
end

a = Animal.new
d = Dog.new
a.make_noise  #=> "whaargarble"
d.make_noise  #=> "bark"
Dog.noise = "WOOF"
d.make_noise  #=> "WOOF"
a.make_noise  #=> "whaargarble"

但是,如果您确定需要常量:

class Animal
  def make_noise
    puts self.class::NOISE
    # or self.class.const_get(:NOISE)
  end
end

答案 1 :(得分:5)

没有类实例变量的一种方法:

class Animal

 def make_noise
   print self.class::NOISE
 end

end

class Dog < Animal
  NOISE = "bark"
end

d = Dog.new
d.make_noise # prints bark

答案 2 :(得分:0)

我认为你的概念错了。 Ruby中的类与Java,Smalltalk,C#中的类类似,并且所有类都是其实例的模板。因此,类定义了结构和行为,如果它的实例,以及它的子类实例的结构和行为的部分但不是反之亦然

因此,根本不可能从超类直接访问子类中的常量,这是一件好事。请参阅下文如何解决它。对于您定义的类,以下是正确的:

  • class Animal定义方法make_noise
  • class Animal的实例可以调用方法make_noise
  • class Dog使用其值定义常量NOISE
  • Dog的实例和类Dog本身可以使用常量NOISE

什么是不可能的:

  • Animal或类Animal的实例本身可以访问类Dog的常量。

您可以通过以下更改来解决此问题:

class Animal
  def make_noise
    print Dog::NOISE
  end
end

但这是不好的风格,因为现在,你的超类(它是关于Dog和其他动物的抽象)现在知道属于Dog的东西。

更好的解决方案是:

  1. 在类Animal中定义一个抽象方法,该方法定义应定义make_noise。请参阅答案https://stackoverflow.com/a/6792499/41540
  2. 再次在具体类中定义方法,但现在引用常量。

答案 3 :(得分:0)

如果您正在执行此操作来配置子类,以便基类可以访问常量,那么您可以为它们创建DSL,如下所示:

module KlassConfig
  def attr_config(attribute)
    define_singleton_method(attribute) do |*args|
      method_name = "config_#{attribute}"
      define_singleton_method method_name do
        args.first
      end
      define_method method_name do
        args.first
      end
    end
  end
end

class Animal
  extend KlassConfig
  attr_config :noise

  def make_noise
    puts config_noise
  end
end

class Dog < Animal
  noise 'bark'
end

这种方式更有效,因为在每个方法调用中,您都不必反省该类以返回(或者它是向前?)常量。

答案 4 :(得分:-1)

如果你想要面向对象的方式(TM),那么我想你想要:

class Animal
  # abstract animals cannot make a noise
end

class Dog < Animal
  def make_noise
    print "bark"
  end
end

class Cat < Animal
  def make_noise
    print "meow"
  end
end

d = Dog.new
d.make_noise # prints bark

c = Cat.new
c.make_noise # prints meow

如果您想重构以防止重复print的代码:

class Animal
  def make_noise
    print noise
  end
end

class Dog < Animal
  def noise
    "bark"
  end
end

class Cat < Animal
  def noise
    if friendly
      "meow"
    else
      "hiss"
    end
  end
end

d = Dog.new
d.make_noise # prints bark

c = Cat.new
c.make_noise # prints meow or hiss