我已经看到了如何将类定义为单例(how to create a singleton in ruby):
require 'singleton'
class Example
include Singleton
end
但是,如果我想为该单个实例提供一些参数,这意味着该示例应该始终初始化某些属性。例如,假设我有一个类,它的唯一目的是记录到一个文件(这只是一个例子),但它需要一个要记录到的文件名才能工作。
class MyLogger
def initialize(file_name)
@file_name = file_name
end
end
我怎样才能让MyLogger成为一个单例,同时又确保它有一个file_name?
发布于 2011-03-10 20:25:31
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
它应该可以工作,但我没有测试代码。
此代码强制您使用MyLogger.instance <file_name>
,或者至少在第一次调用时使用,如果您知道它将是第一次调用的话。
发布于 2011-08-01 14:23:00
这是另一种方法--将日志文件名放在一个类变量中:
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
现在你可以这样使用它:
MyLogger.file_name = "path/to/log/file"
log = MyLogger.instance # => #<MyLogger:0x000.... @file_name="path/to/log/file">
后续对instance
的调用将返回相同的对象,但路径名不变,即使您稍后更改了类变量的值也是如此。一个不错的进一步尝试是使用另一个类变量来跟踪实例是否已经创建,并在这种情况下让file_name=
方法引发异常。如果尚未设置@@file_name
,也可以让initialize
引发异常。
发布于 2018-08-12 04:23:25
这是我用来解决类似问题的一种方法,我想分享一下,以防你或其他人觉得合适:
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.3
、2.4
和2.5
中测试了这些代码;当然,早期版本可能会表现出不同的行为。
这允许您拥有一个通用的参数化Logger
类,它可以用来创建额外的实例,用于测试或将来的替代配置,同时将MyLogger
定义为它的一个实例,遵循Singleton
的标准化模式。您可以根据需要将实例方法拆分到它们之间。
Ruby的Singleton
在第一次需要时会自动构造实例,所以Logger#initialize
参数在MyLogger.new
中必须是按需可用的,但您当然可以在使用单例实例之前的配置过程中从环境中提取这些值或将它们设置为MyLogger
类实例变量,这与单例实例实际上是全局的一致。
https://stackoverflow.com/questions/5259398
复制相似问题