Learning Ruby Singleton Pattern

1. 为什么需要 Singleton Pattern

Singleton Pattern(单例模式),是用来保证某个类的实例只有一个。
参考下面的英文原文:
Singleton is a design pattern that restricts instantiation of a class to only one instance that is globally available. It is useful when you need that instance to be accessible in different parts of the application, usually for logging functionality, communication with external systems, database access, etc.

2. 如何用 Ruby 实现 Singleton Pattern

2.1 使用 Ruby 内部 Singleton 库。
源代码文件目录:ruby/lib/singleton.rb

    require 'singleton'

    class Foo

      include Singleton

    end

    ObjectSpace.each_object(Foo){}
    => 0

    a,b = Foo.instance, Foo.instance
    => [#< Foo:0x007fcdf5234c20>, #< Foo:0x007fcdf5234c20>]
    # 对象所对应的内存地址都是一样的

    a == b
    => true

    ObjectSpace.each_object(Foo){}
    => 1
  

该 Singleton module 包含以下方法:

    # instance_methods:
      clone
      dup
      _dump

    # class_methods:
      instance

      # private
      new
      allocate
  

Ruby Singleton module 源代码内部注释:

    # The Singleton module implements the Singleton pattern.
    # To use Singleton, include the module in your class.
    # This ensures that only one instance of Klass can be created.
    # The instance is created at upon the first call of Klass.instance().

    # This above is achieved by:
    # *  Making Klass.new and Klass.allocate private.
    #
    # *  Overriding Klass.inherited(sub_klass) and Klass.clone() to
    #    ensure that the Singleton properties are kept
    #    when inherited and cloned.
    #
    # *  Providing the Klass.instance() method that returns the
    #    same object each time it is called.
    #
    # *  Overriding Klass._load(str) to call Klass.instance().
    #
    # *  Overriding Klass#clone and Klass#dup to raise TypeErrors to
    #    prevent cloning or duping.
  

2.2 使用类或模块
Ruby 把类作为对象来处理,在类或模块里定义一个方法,就是实现 Singleton Pattern.

    require 'singleton'

    class Foo

      include Singleton

    end

    ObjectSpace.each_object(Foo){}
    => 0

    a,b = Foo.instance, Foo.instance
    => [#< Foo:0x007fcdf5234c20>, #< Foo:0x007fcdf5234c20>]
    # 对象所对应的内存地址都是一样的

    a == b
    => true

    ObjectSpace.each_object(Foo){}
    => 1
  

2.3 使用对象,结合动态添加方法
在对象生成之后,为实例添加新的方法,该方法就是 Singleton 方法。

    class Foo
    end

    Foo.singleton_methods
    => []

    a,b = Foo.new, Foo.new
    => [#< Foo:0x007f87cacaf478 >, #< Foo:0x007f87cacaf450 >]

    # 添加 Singleton 方法
    def a.greeting
      "Hello singleton method"
    end

    # 未引起 Foo Class 的变化
    Foo.singleton_methods
    => []

    Foo.instance_methods.include?("greeting")
    => false


    a.greeting
    => "Hello singleton method"

    a.singleton_methods
    => [:greeting]

    # 未引起 b 实例的变化
    b.singleton_methods
    => []

    b.greeting
    NoMethodError: undefined method `greeting' for #< Foo:0x007f87cacaf450 >
  

2.4 把一般对象作为 Singleton 来使用
为了保证一个类的对象只有一个,可以在生成一个实例之后,不再生成其他对象。
PS:现实中不太容易保证。

2013-05-03

rocket-wing