Ruby Singleton Classes
Bài đăng này đã không được cập nhật trong 8 năm
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