@Readonly
如果您对“class MyObject”的使用是对开放类的使用,那么请注意您正在重新定义初始化方法。
在 Ruby 中,没有重载之类的东西......只有覆盖或重新定义......换句话说,任何给定方法只能有 1 个实例,所以如果你重新定义它,它就会被重新定义......并且initialize方法没有什么不同(尽管它是Class对象的新方法使用的)。
因此,在没有先给它起别名的情况下,永远不要重新定义现有方法……至少如果你想访问原始定义的话。而且重新定义一个未知类的初始化方法可能是相当冒险的。
无论如何,我想我有一个更简单的解决方案,它使用实际的元类来定义单例方法:
m = MyObject.new
metaclass = class << m; self; end
metaclass.send :attr_accessor, :first, :second
m.first = "first"
m.second = "second"
puts m.first, m.second
您可以同时使用元类和开放类来变得更加棘手,并执行以下操作:
class MyObject
def metaclass
class << self
self
end
end
def define_attributes(hash)
hash.each_pair { |key, value|
metaclass.send :attr_accessor, key
send "#{key}=".to_sym, value
}
end
end
m = MyObject.new
m.define_attributes({ :first => "first", :second => "second" })
上面基本上是通过“metaclass”方法暴露元类,然后在define_attributes中用attr_accessor动态定义一堆属性,然后用hash中的关联值调用属性setter。
使用 Ruby,您可以发挥创造力并以多种不同方式做同样的事情 ;-)
仅供参考,如果您不知道,像我所做的那样使用元类意味着您只对给定的对象实例进行操作。因此,调用 define_attributes 只会为该特定实例定义那些属性。
例子:
m1 = MyObject.new
m2 = MyObject.new
m1.define_attributes({:a => 123, :b => 321})
m2.define_attributes({:c => "abc", :d => "zxy"})
puts m1.a, m1.b, m2.c, m2.d # this will work
m1.c = 5 # this will fail because c= is not defined on m1!
m2.a = 5 # this will fail because a= is not defined on m2!