首页 > 解决方案 > 双管有没有实际区别|| 和 Ruby 中的单例?

问题描述

昨天我在阅读有关 Ruby 的文章并达到了 Singleton 的概念,其中提到用于避免多次实例化一个类。

我以前不知道这个概念,但是当我想达到这个目的时,我正在创建一个全局变量并使用双管道 || 反而。

例如:

@browser ||= Browser.new

在某些情况下是否有任何区别或优势可以更好地使用 Singleton?

标签: rubysingleton

解决方案


||=用于记忆一个值。例如,如果您有一个方法执行昂贵的操作或返回一个变化的值:

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是一个实例变量,所以每个实例都存储一个单独的值:

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

另一方面,单例确保给定类(每个进程)有一个(并且只有一个)实例,例如

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

那是因为fandg指的是同一个对象。包括Singleton删除通过newor创建任何其他实例的能力allocate

Foo.new      #=> NoMethodError
Foo.allocate #=> NoMethodError

推荐阅读