双管之间有什么实际区别?和Ruby中的单身人士?

时间:2018-06-21 09:16:17

标签: ruby singleton

昨天我正在阅读有关Ruby的内容,并达到了Singleton的概念,该概念用于避免多次实例化一个类。

我以前不了解这个概念,但是当我想实现这个目的时,我正在创建一个全局变量并使用双管道||。代替。

例如:

@browser ||= Browser.new

在某些情况下是否存在任何区别或优势,这将使Singleton的使用更好?

2 个答案:

答案 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

这是因为fg指的是同一对象。包含Singleton将使您无法通过newallocate创建任何其他实例:

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"

我认为在很多情况下,单例课程实际上是解决问题的最佳方法。