首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >ruby -创建带参数的单例?

ruby -创建带参数的单例?
EN

Stack Overflow用户
提问于 2011-03-10 20:08:54
回答 4查看 10.7K关注 0票数 19

我已经看到了如何将类定义为单例(how to create a singleton in ruby):

代码语言:javascript
复制
require 'singleton'

class Example
  include Singleton
end

但是,如果我想为该单个实例提供一些参数,这意味着该示例应该始终初始化某些属性。例如,假设我有一个类,它的唯一目的是记录到一个文件(这只是一个例子),但它需要一个要记录到的文件名才能工作。

代码语言:javascript
复制
class MyLogger
  def initialize(file_name)
    @file_name = file_name
  end
end

我怎样才能让MyLogger成为一个单例,同时又确保它有一个file_name?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-03-10 20:25:31

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

代码语言:javascript
复制
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

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

此代码强制您使用MyLogger.instance <file_name>,或者至少在第一次调用时使用,如果您知道它将是第一次调用的话。

票数 4
EN

Stack Overflow用户

发布于 2011-08-01 14:23:00

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

代码语言:javascript
复制
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

现在你可以这样使用它:

代码语言:javascript
复制
MyLogger.file_name = "path/to/log/file"
log = MyLogger.instance  # => #<MyLogger:0x000.... @file_name="path/to/log/file">

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

票数 16
EN

Stack Overflow用户

发布于 2018-08-12 04:23:25

这是我用来解决类似问题的一种方法,我想分享一下,以防你或其他人觉得合适:

代码语言:javascript
复制
require 'singleton'

class Logger
  attr_reader :file_name

  def initialize file_name
    @file_name = file_name
  end
end


class MyLogger < Logger
  include Singleton

  def self.new
    super "path/to/file.log"
  end

  # You want to make {.new} private to maintain the {Singleton} approach;
  # otherwise other instances of {MyLogger} can be easily constructed.
  private_class_method :new
end

p MyLogger.instance.file_name
# => "path/to/file.log"

MyLogger.new "some/other/path"
# => ...private method `new' called for MyLogger:Class (NoMethodError)

我已经在2.32.42.5中测试了这些代码;当然,早期版本可能会表现出不同的行为。

这允许您拥有一个通用的参数化Logger类,它可以用来创建额外的实例,用于测试或将来的替代配置,同时将MyLogger定义为它的一个实例,遵循Singleton的标准化模式。您可以根据需要将实例方法拆分到它们之间。

Ruby的Singleton在第一次需要时会自动构造实例,所以Logger#initialize参数在MyLogger.new中必须是按需可用的,但您当然可以在使用单例实例之前的配置过程中从环境中提取这些值或将它们设置为MyLogger类实例变量,这与单例实例实际上是全局的一致。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5259398

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档