ruby - 用参数创建单例?

cod*_*aig 17 ruby singleton

我已经看到如何将类定义为单例(如何在ruby中创建单例):

require 'singleton'

class Example
  include Singleton
end
Run Code Online (Sandbox Code Playgroud)

但是,如果我想为该单个实例提供一些参数,这意味着,示例应始终具有初始化的某些属性.例如,假设我有一个类,其唯一目的是登录文件(这只是一个示例),但它需要一个文件的名称才能在它可以工作之前登录.

class MyLogger
  def initialize(file_name)
    @file_name = file_name
  end
end
Run Code Online (Sandbox Code Playgroud)

如何使MyLogger成为单例,但确保它获得file_name?

Jan*_*ich 15

这是另一种方法 - 将日志文件名放在类变量中:

require 'singleton'
class MyLogger
  include Singleton
  @@file_name = ""
  def self.file_name= fn
    @@file_name = fn
  end
  def initialize
    @file_name = @@file_name
  end
end
Run Code Online (Sandbox Code Playgroud)

现在你可以这样使用它:

MyLogger.file_name = "path/to/log/file"
log = MyLogger.instance  # => #<MyLogger:0x000.... @file_name="path/to/log/file">
Run Code Online (Sandbox Code Playgroud)

instance即使您稍后更改了类变量的值,后续调用也将返回路径名未更改的同一对象.进一步的好处是使用另一个类变量来跟踪是否已经创建了一个实例,并且file_name=在这种情况下让该方法引发异常.initialize如果@@file_name尚未设置,您也可以引发异常.

  • 为什么要打扰将@@ file_name复制到@file_name而不是仅仅使用@@ file_name(如果它是单例)? (3认同)

mpa*_*pis 4

Singleton不提供此功能,但是您可以自己编写它,而不是使用singleton

class MyLogger
  @@singleton__instance__ = nil
  @@singleton__mutex__    = Mutex.new

  def self.instance(file_name)
    return @@singleton__instance__ if @@singleton__instance__

    @@singleton__mutex__.synchronize do
      return @@singleton__instance__ if @@singleton__instance__

      @@singleton__instance__ = new(file_name)
    end
    @@singleton__instance__
  end

  private

  def initialize(file_name)
    @file_name = file_name
  end
  private_class_method :new
end
Run Code Online (Sandbox Code Playgroud)

它应该可以工作,但我没有测试代码。

MyLogger.instance <file_name>如果您知道这将是第一次调用,此代码会强制您至少在第一次调用时使用or 。