【问题标题】:What is the correct way to write a singleton pattern in Ruby?在 Ruby 中编写单例模式的正确方法是什么?
【发布时间】:2009-09-27 02:02:26
【问题描述】:

我正在尝试用 Ruby 编写最安全的单例。我是这门语言的新手,它非常有弹性,以至于我没有强烈的感觉,我的单例课程只会成功创建一个实例。作为奖励,我希望该对象仅在真正使用时才被实例化。

【问题讨论】:

    标签: ruby design-patterns singleton


    【解决方案1】:
    # 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 的类方法,该方法仅实例化该类的一个实例。

    所以要使用 ruby​​ 单例模块,你需要两件事:

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

    【讨论】:

      【解决方案2】:

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

      >> 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 代码应该(恕我直言)使用鸭子类型(通过#respond_to?)而不是显式检查对象的类,所以我通常不关心我的单例对象类的唯一性,因为它不是它的类它是独一无二的,但我之后添加的所有内容。

      【讨论】:

      • +1 指出并不真正需要单例。您可以在不盲目复制模式的情况下实现意图。
      • 我一直在认真思考这一点,因为它对 ruby​​ 核心中 Singleton 模块的存在提出了质疑。带有 Singleton mixin 的类的潜在效用对我来说是双重的:1)如果你想要类和实例方法,以及 2)如果你有复杂的初始化,你想懒惰地运行而不需要模块方法以某种方式显式地触发它第一次访问它们。其他人有任何实际单例模块的​​优势吗?
      【解决方案3】:
      require 'singleton'
      class Klass
          include Singleton
          # ...
      end
      

      请参阅Ruby Standard Library Singleton class documention 了解说明。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-22
        相关资源
        最近更新 更多