2009-09-27 62 views
25

我正在尝试在Ruby中编写最安全的单例。我对这门语言很陌生,因为它非常有弹性,所以我没有强烈的感觉,我的单身人士课程只会成功创建一个实例。作为奖励,我希望该对象只在实际使用时才能实例化。在Ruby中编写单例模式的正确方法是什么?

回答

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. 它增加了一个名为实例的类方法,它只实例化该类的一个实例。

所以使用Ruby单模块需要两样东西:

  1. 需要的lib singleton则包括它所需的类中。
  2. 使用instance方法获取您需要的实例。
16

如果你想创建一个单例,为什么要麻烦创建一个类?只需创建一个对象,并将方法和实例变量添加到您想要的。

人们实现这种模式
>> 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使它变得非常简单,并且不像其他语言,它不需要在类中定义。

临时单身人士(我的第一个例子)遍布整个地方,涵盖了我遇到的大多数情况。模块技巧通常涵盖其余部分(当我想要一些更正式的东西时)。

Ruby代码应该使用duck typing(通过#respond_to?)而不是明确地检查一个对象的类,所以我通常不关心我的singleton对象的类的唯一性,因为它不是它的类使它独一无二的,但我添加后的一切。

+6

+1指出单身并不是真的需要。你可以实现这个意图,而不会无情地复制模式。 – 2009-09-28 12:30:46

+0

我一直在想这个问题,因为它引发了Ruby中coreton模块的存在。这个class/w/Singleton mixin的潜在用途有两方面的含义:1)如果你想要类和实例方法,并且2)如果你有复杂的初始化,你想懒惰地运行而不需要模块方法以某种方式明确地触发它他们第一次访问。其他人是否有实际的Singleton模块的优点? – gtd 2011-10-12 02:38:13

相关问题