我知道单例方法存在于单例类(或特征类)中。我的第一个问题是:
为什么它们不能生活在物体内部?我知道在 ruby 中,一个对象只能保存实例变量。但我不明白为什么单例方法没有设计成对象。
下一个,
如果对象只能包含实例变量,那么作为 Class 的对象的类怎么能存储方法呢?
我只是在概念层面上感到困惑。我读过很多次 ruby 对象模型是一致的。
我知道单例方法存在于单例类(或特征类)中。我的第一个问题是:
为什么它们不能生活在物体内部?我知道在 ruby 中,一个对象只能保存实例变量。但我不明白为什么单例方法没有设计成对象。
下一个,
如果对象只能包含实例变量,那么作为 Class 的对象的类怎么能存储方法呢?
我只是在概念层面上感到困惑。我读过很多次 ruby 对象模型是一致的。
广告 1,它们确实存在于对象内部。事实上,单例类只是一种心理结构。这里的“单例”意味着,根据定义,该类只有一个实例——那个对象。所以对象的身份和单例类是密不可分的。
广告 2,答案是,因为 Matz 如此决定。更准确地说,不是类,而是模块(Module 类)存储方法,并且Class < Module
.
您可能会感兴趣,默认情况下不实例化对象的单例类。在您尝试访问它之前,它根本不存在。这是因为如果所有单例类都立即实例化,您将拥有一个无限的单例类链:
o = Object.new
o.singleton_class
o.singleton_class.singleton_class
o.singleton_class.singleton_class.singleton_class
...
单例模式的目标是确保特定类中只有一个对象存在于系统中。
所以这些方法仍然存在于一个类中,但是您不能创建该类的另一个实例。
一个类是一个对象,但是因为它作为其他对象的模板,它自己的实例,它把它们的实例方法保存在它的模块中。但是,如果您将一个类视为普通对象,例如调用#object_id
它,它会为您提供普通对象所期望的所有行为。
Module
继续我们在评论中的讨论:严格来说,存储方法(和常量)的能力是模块(类)的内置特殊能力。Class
class 恰好是 class 的子Module
类,这使得它继承了模块存储方法的能力,但是您可以自由地创建具有该能力的其他对象(不仅仅是类):
class MyPetObjectThatCanStoreMethods < Module
def greet; puts "Bow, wow!" end
end
Fred = MyPetObjectThatCanStoreMethods.new
因此,Fred
它不完全是一个模块,而是来自Module
并具有存储方法和常量的能力:
module Fred # this is allowed!
LENGTH = 19
def rise; puts "I'm rising!" end
end
您不能对普通对象执行此操作,只能使用模块后代!
Fred::LENGTH #=> 19
Fred.greet
#=> Bow, wow!
Fred.rise
#=> NoMethodError
那是因为Fred
stores #rise
方法,就像模块一样,但不像#greet
方法,#rise
不是它的实例方法!为了访问它,我们必须Fred
在一个合适的类中包含:
o = Object.new
o.rise
#=> NoMethodError
class << o # Including Fred in the metaclass of o
include Fred
end
o.rise
#=> I'm rising!
如果对象只能包含实例变量,那么作为 Class 的对象的类怎么能存储方法呢?
class Foo
def suprim;end
end
Foo.instance_methods(true).grep(/^sup/)
#=> [:suprim]
我搜索了Class的实例方法superclass
,但没有出现,因为Foo
是的实例Class
,所以它不应该存储的实例方法Class
。但是,是的,Foo
只返回要使用的实例的方法。这是自然的。现在看下面:
Class.instance_methods(true).grep(/^sup/)
#=>[:superclass]