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

例如:

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 

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

 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 

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

 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 

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

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

  • class Animal定义方法make_noise
  • class Animal实例可以调用方法make_noise
  • class Dog用它的值定义常量NOISE
  • Dog和class 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. 再次在您的具体类中定义该方法,但现在引用该常量。

如果您这样做是为了配置您的子类以便基类可以访问常量,那么您可以为它们创建一个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 

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

如果你想要面向对象的方式(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