Ruby类实例变量和继承

rla*_*ter 18 ruby class instance-variables

我有一个叫做Ruby的类LibraryItem.我想将此类的每个实例与一组属性相关联.这个数组很长,看起来像

['title', 'authors', 'location', ...]
Run Code Online (Sandbox Code Playgroud)

请注意,这些属性实际上不应该是方法,只是一个属性列表LibraryItem.

接下来,我想创建一个LibraryItem被调用的子类,LibraryBook它具有包含所有属性的属性数组,LibraryItem但也包含更多属性.

最终,我会想的几个子类LibraryItem每一个都有自己的版本阵@attributes上,但每个加入LibraryItem@attributes(如LibraryBook,LibraryDVD,LibraryMap,等).

所以,这是我的尝试:

class LibraryItem < Object
  class << self; attr_accessor :attributes; end
  @attributes = ['title', 'authors', 'location',]
end

class LibraryBook < LibraryItem
  @attributes.push('ISBN', 'pages')
end
Run Code Online (Sandbox Code Playgroud)

这不起作用.我收到了错误

undefined method `push' for nil:NilClass
Run Code Online (Sandbox Code Playgroud)

如果要工作,我会想要这样的东西

puts LibraryItem.attributes 
puts LibraryBook.attributes
Run Code Online (Sandbox Code Playgroud)

输出

['title', 'authors', 'location']
['title', 'authors', 'location', 'ISBN', 'pages']
Run Code Online (Sandbox Code Playgroud)

(2010年5月2日添加)对此的一个解决方案是创建@attributes一个简单的实例变量,然后LibraryBootinitialize方法中添加新属性(这是demas在其中一个答案中建议的).

虽然这肯定会起作用(事实上,我一直都在做),但我对此并不满意,因为它是次优的:为什么每次创建对象时都要构造这些不变的数组?

我真正想要的是拥有可以从父类继承的类变量,但是在子类中更改时不会在父类中更改.

tom*_*azy 11

另一个解决方案是使用继承的钩子:

class LibraryItem < Object
  class << self
    attr_accessor :attributes
    def inherit_attributes(attrs)
      @attributes ||= []
      @attributes.concat attrs
    end

    def inherited(sublass)
      sublass.inherit_attributes(@attributes)
    end
  end
  @attributes = ['title', 'authors', 'location',]
end

class LibraryBook < LibraryItem
  @attributes.push('ISBN', 'pages')
end
Run Code Online (Sandbox Code Playgroud)


bta*_*bta 9

既然你提到属性是"固定的"和"不变的",我假设你的意思是你创建对象后永远不会改变它们的值.在这种情况下,类似下面的东西应该工作:

class Foo
    ATTRS = ['title', 'authors', 'location']
    def attributes
        ATTRS
    end
end

class Bar < Foo
    ATTRS = ['ISBN', 'pages']
    def attributes
        super + ATTRS
    end
end
Run Code Online (Sandbox Code Playgroud)

您正在手动实现一个读取器方法(而不是让它attr_accessor为您创建),它伪装了数组的内部名称.在您的子类中,您只需调用祖先类的reader函数,添加与子类关联的其他字段,并将其返回给调用者.对于用户来说,这看起来像一个只读的成员变量attributes,在子类中有其他值.


dem*_*mas 5

就像一个版本:

class LibraryItem < Object
  def initialize
    @attributes = ['one', 'two'];
  end
end

class LibraryBook < LibraryItem
  def initialize
   super
   @attributes.push('three')
 end
end

b = LibraryBook.new
Run Code Online (Sandbox Code Playgroud)