0

Ruby Singleton Classes

Today I want to write something which so strange when first heard of while starting to learn Ruby programming: Singleton class.

1.What is Singleton Class

Ruby provides a way to define methods that are specific to a particular object and such methods are known as Singleton Methods. When one declares a singleton method on an object, Ruby automatically creates a class to hold just the singleton methods. The newly created class is called Singleton Class.

Now, in Ruby, all objects have a class that it is an instance of. You can find this class by calling the method class on any object. The methods an object respond to will originally be the ones in that objects class.

To the Ruby interpreter, there is no difference in this case. Now, if foo is a String, the method bar will be available to call on the object referenced by foo, but not on any other Strings. The way this works is that the first time a method on a specific object is defined, a new, anonymous class will be inserted between the object and the real class. So, when I try to call a method on foo, the interpreter will first search inside the anonymous class for a definition, and then go on searching the real class hierarchy for an implementation. As you probably understand, that anonymous class is our singleton class.

2.Characteristics of Singleton Class

Ruby has singleton methods that function similarly to 'class' or 'static' methods in languages like Java, but the implementation is different. Ruby's 'class methods' are really just instance methods defined in the singleton class. Ruby doesn't have static methods like Java.

Only one object can be created

 class Foo
    class << self
      def instance
        @instance ||= new
      end

      private :new
    end
  end

 # access the instance
 Foo.instance # => #<Singleton:0x007fd70c889880>

 # cannot instantiate
 Singleton.new # ~> -:12:in `<main>': private method `new' called for Singleton:Class (NoMethodError)

3.Ways to create Singleton Class

  • ####Create methods with object.method
word = String.new
def word.length
	"count what?"
end
word.length  # => "count what?"
word.class # => String
another_word = String.new
another_word.length # => 0

- ####Create methods from Module
```Ruby

module Foo
  def foo
    "Module!"
  end
end
foo = ""
foo.extend(Foo)
foo.singleton_methods # => ["foo"]

  • Opening Singleton Class Directly

Anytime you see a strange looking class definition where the class keyword is followed by two less than symbols, you can be sure that a singleton class is being opened f or the object to the right of those symbols. In this example, the singleton class for the foobar object is being opened. As you probably already know, Ruby allows you to reopen a class at any point adding methods and doing anything you could have done in the original class definition. As with the rest of the examples in this section a foo method is being added to the foobar singleton class.


foobar = ""
class << foobar
  def foo
    "Singleton class"
  end
end
foobar.singleton_methods # => [:foo]

  • ####Evaluating Code in the context of Object

foo = ""
foo.instance_eval <<EOT
	def foo
		"What is this?"
	end
EOT
foo.singleton_methods # => [:foo]

###4.Practical use of Singleton Class

I want also introduce the use of singleton module. A class mixing in the Singleton module is functionally equivalent to a class or module with 'class' methods and either a guaranteed initialization call or inline initialization. Compare this usage of Singleton:


require 'singleton'
class Bar
  include Singleton
  attr_reader :count
  def initialize
    @count = 0
  end
  def increase
    @count += 1
  end
end

b1 = Bar.instance
b1.increase
b2 = Bar.instance
b2.increase
p b1.increase         #=> 2

module Foo
  @count = 0
  def self.increase
    @count *= 2
  end
  def self.count
    @count
  end
end

Foo.increase
Foo.increase
p Foo.count        #=> 2

In both cases you have a single global object that maintains state. (Because every constant you create in the global scope, including classes and modules, is a global object.)

The only functional difference is that with the Singleton you delay the initialization of the object until the first time you ask for it.

So, if you ever have 'class' methods on a class or module and you use those to change the state of that object (e.g. a class keeping track of all subclasses that inherit from it) you are essentially using a singleton.

###5.Conclusion

I hope you like this post and I welcome for any comments or questions to make this post better.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí