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一个简单的实例变量,然后LibraryBoot在initialize方法中添加新属性(这是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)
既然你提到属性是"固定的"和"不变的",我假设你的意思是你创建对象后永远不会改变它们的值.在这种情况下,类似下面的东西应该工作:
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,在子类中有其他值.
就像一个版本:
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)