在Ruby中编写单例模式的正确方法是什么?

时间:2009-09-27 02:02:26

标签: ruby design-patterns singleton

我正在尝试用Ruby编写最安全的单例。我对这种语言很陌生,这种语言很有弹性,我没有强烈的感觉,我的单例类只能创建一个实例。作为奖励,我希望该对象只有在真正使用时才会被实例化。

3 个答案:

答案 0 :(得分:43)

# require singleton lib
require 'singleton'
class AppConfig
  # mixin the singleton module
  include Singleton
  # do the actual app configuration
  def load_config(file)
    # do your work here
    puts "Application configuration file was loaded from file: #{file}"
  end
end

conf1 = AppConfig.instance
conf1.load_config "/home/khelll/conf.yml"
#=>Application configuration file was loaded from file: /home/khelll/conf.yml
conf2 = AppConfig.instance
puts conf1 == conf2
#=>true
# notice the following 2 lines won’t work
AppConfig.new rescue(puts $!)
#=> new method is private
# dup won’t work
conf1.dup rescue(puts $!)
#=>private method `new’ called for AppConfig:Class
#=>can’t dup instance of singleton AppConfig

那么当你在课堂中包含单例模块时,ruby会怎么做?

  1. 它使new方法变为私有,因此您无法使用它。
  2. 它添加了一个名为instance的类方法,该方法只实例化该类的一个实例。
  3. 因此,要使用ruby singleton模块,您需要做两件事:

    1. 需要lib singleton,然后将其包含在所需的类中。
    2. 使用instance方法获取所需的实例。

答案 1 :(得分:17)

如果你想创建一个单例,为什么还要创建一个类呢?只需创建一个对象,然后将方法和实例变量添加到所需的对象中。

>> MySingleton = Object.new
=> #<Object:0x100390318>
>> MySingleton.instance_eval do
?>   @count = 0
>>   def next
>>     @count += 1
>>   end
>> end
=> nil
>> MySingleton.next
=> 1
>> MySingleton.next
=> 2
>> MySingleton.next
=> 3

人们实现此模式的一种更标准的方法是使用Module作为单例对象(而不是更通用的Object):

>> module OtherSingleton
>>   @index = -1
>>   @colors = %w{ red green blue }
>>   def self.change
>>     @colors[(@index += 1) % @colors.size]
>>   end
>> end
=> nil
>> OtherSingleton.change
=> "red"
>> OtherSingleton.change
=> "green"
>> OtherSingleton.change
=> "blue"
>> OtherSingleton.change
=> "red"

如果您希望单个对象从某个类继承,只需将其作为该类的实例即可。要从mixin继承,只需使用#extend。如果你想要一个单例对象,ruby使它变得非常容易,而且与其他语言不同,它不必在类中定义。

Ad-hoc单身人士(我的第一个例子)到处都是,涵盖了我遇到的大多数情况。模块技巧通常涵盖其余部分(当我想要更正式的东西时)。

Ruby代码应该(imho)使用duck typing(通过#respond_to?)而不是显式检查对象的类,所以我通常不关心我的单例对象类的唯一性,因为它不是它的类这使得它独一无二,但我之后添加了所有内容。

答案 2 :(得分:8)

require 'singleton'
class Klass
    include Singleton
    # ...
end

有关说明,请参阅Ruby Standard Library Singleton class documention