昨天我正在阅读有关Ruby的内容,并达到了Singleton的概念,该概念用于避免多次实例化一个类。
我以前不了解这个概念,但是当我想实现这个目的时,我正在创建一个全局变量并使用双管道||。代替。
例如:
@browser ||= Browser.new
在某些情况下是否存在任何区别或优势,这将使Singleton的使用更好?
答案 0 :(得分:2)
||=
用于memoize值。例如,如果您有执行昂贵的操作或返回可变值的方法:
class Foo
def now
Time.now
end
end
f = Foo.new
f.now #=> 2018-06-21 11:59:56 +0200
f.now #=> 2018-06-21 11:59:59 +0200
f.now #=> 2018-06-21 12:00:02 +0200
您想缓存该值,||=
是您的朋友:
class Foo
def now
@now ||= Time.now
end
end
f = Foo.new
f.now #=> 2018-06-21 11:59:56 +0200
f.now #=> 2018-06-21 11:59:56 +0200
f.now #=> 2018-06-21 11:59:56 +0200
第一个调用调用Time.now
并将结果分配给@now
。后续调用仅返回@now
,而无需评估右侧。因此,Time.now
仅被调用一次,该方法的返回值不再更改。
并且由于@now
是 instance 变量,因此每个实例存储一个单独的值:
f = Foo.new
f.now #=> 2018-06-21 11:59:56 +0200
f.now #=> 2018-06-21 11:59:56 +0200
f.now #=> 2018-06-21 11:59:56 +0200
g = Foo.new
f.now #=> 2018-06-21 12:00:02 +0200
f.now #=> 2018-06-21 12:00:02 +0200
f.now #=> 2018-06-21 12:00:02 +0200
另一方面,singleton确保给定类(每个进程)只有一个(只有一个)实例,例如:
require 'singleton'
class Foo
include Singleton
def now
@now ||= Time.now
end
end
f = Foo.instance
f.now #=> 2018-06-21 11:59:56 +0200
f.now #=> 2018-06-21 11:59:56 +0200
g = Foo.instance
g.now #=> 2018-06-21 11:59:56 +0200
g.now #=> 2018-06-21 11:59:56 +0200
这是因为f
和g
指的是同一对象。包含Singleton
将使您无法通过new
或allocate
创建任何其他实例:
Foo.new #=> NoMethodError
Foo.allocate #=> NoMethodError
答案 1 :(得分:1)
如果变量未定义或包含假值(nil或false),则Ruby中的||=
运算符将为该变量设置一个值。
a = 1
a ||= 2 # a is already set to 1 so it stays 1.
a = false
a ||= 1 # a was falsey, it is now set to 1.
这通常用于记住方法的返回值,以减少不必要的重新计算:
class Foo
def value
@value ||= 1+1
end
end
Foo.new.value # @value was undefined so it set to 1+1 = 2
Foo.new.value # @value was already defined so return it instead of recalculating
单例类是只能有一个实例的类。
常规的非单例课程:
class Foo
end
# create two instances:
foo1 = Foo.new
foo2 = Foo.new
foo1 == foo2 # => false
单例课程:
require 'singleton'
class Foo
include Singleton
def test
"hello"
end
end
# you can't create an instance:
foo = Foo.new # => NoMethodError (private method `new' called for Foo:Class)
# there is one global instance:
foo1 = Foo.instance
foo2 = Foo.instance
foo1 == foo2 # => true
# the Singleton module does not enable you to call the instance methods directly:
Foo.test # => NoMethodError (private method `test' called for Foo:Class)
Foo.instance.test # => "hello"
我认为在很多情况下,单例课程实际上是解决问题的最佳方法。