我正在阅读有关 Ruby 中的单例的信息。我以前从来没有真正需要使用它们,但我很好奇并决定查找它们,看看我过去是否应该使用它们,或者如果我知道它们是什么,也许我将来可以使用它们用于。
我能想到使用它的唯一时间是:
- ? 当我需要一个特殊的对象时。示例:“智能”
Hash
对象,其行为类似于普通的 Ruby 哈希,但有一些额外的怪癖。 - 当我想让它只存在一个类的实例时。
但是,我不确定我是否需要上述任何一种。
请注意,单例模块中的类混合在功能上等同于具有“类”方法的类或模块,并且可以保证初始化调用或内联初始化。比较 Singleton 的这种用法:
require 'singleton'
class Bar
include Singleton
attr_reader :jam
def initialize
@jam = 42
end
def double
@jam *= 2
end
end
b1 = Bar.instance
b1.double
b2 = Bar.instance
b2.double
p b1.jam #=> 168
使用这个无魔法的模块:
module Foo
@jam = 42
def self.double
@jam *= 2
end
def self.jam
@jam
end
end
Foo.double
Foo.double
p Foo.jam #=> 168
在这两种情况下,您都有一个维护状态的全局对象。(因为您在全局范围内创建的每个常量,包括类和模块,都是一个全局对象。)
唯一的功能区别是Singleton
您将对象的初始化延迟到您第一次请求它。
因此,如果您曾经在一个类或模块上拥有“类”方法,并且您使用这些方法来更改该对象的状态(例如,一个类跟踪从它继承的所有子类),那么您实际上是在使用单例。
您在 Ruby 中一直使用单例类。事实上,每个对象都有一个单例类。(注意:出于性能原因,单例类实际上只在您第一次访问它们时创建,但这是一种性能优化。语义上,每次您尝试查看单例类时,它都会出现。)
例如,所谓的“类方法”实际上并不存在于 Ruby 中。它们只是类对象的单例类的常规实例方法。(改用“类方法”要容易得多。)
每次使用def foo.bar
语法定义方法时,都会将方法添加到foo
.
就像你说的,当你只需要一个类的实例时,就需要一个 Singleton 类。在广泛接受的框架中,Singleton 类的一个很好的例子是 Rails Logger 类。
你的第二个要点是正确的。将单例类视为完全静态的对象。ruby 中的 Boolean 和 Null 对象就是示例。