单例模式是一种常用的设计模式,在ruby的标准库中有singleton模块,可以直接像下面这样使用:
require 'Singleton'
class Test
include Singleton
end
a, b = Test.instance, Test.instance
puts a==b #=>true
如果不使用标准库,该如何实现呢?在看完《ruby元编程》第五章后,似乎有了一些思路决定自己实现一个(备注:和标准库的实现方式可能不一致,还没有看过标准库)。首先需要一些准备知识:钩子函数Hook Method(回调函数),Ruby在做一些事情的时候,会回调一些函数。如继承。例子代码如下:
class String
def self.inherited(subclass)
puts "#{self} was inherited by #{subclass}"
end
end
class T < String; end
String was inherited by T
还有其它很多的钩子函数,这里用到的一个就是included方法,当模块被包含的时候,会调用该方法。例子代码如下:
module M
def self.included(base)
puts "#{self} included by #{base}"
end
end
class Test
include M
end
# => M included by Test
module Singleton
def self.included(base)
base_eigenclass = class << base; self; end
base_eigenclass.class_eval do
instance_variable_set("@instance", base.new)
define_method :instance do
instance_variable_get "@instance"
end
end
end
end
# test for singleton
class Test
include Singleton
end
a, b = Test.instance, Test.instance
puts a==b #=>true
module Singleton
def self.included(base)
base_eigenclass = class << base; self; end
base_eigenclass.class_eval do
instance_variable_set("@instance", base.new)
define_method :instance do
instance_variable_get "@instance"
end
define_method :new do
raise "can't new in singleton class"
end
end
end
end
class Test
include Singleton
end
a = Test.instance
module Singleton
def self.included(base)
base.instance_variable_set("@instance", base.new)
base.extend(self)
end
def new
raise "can't new in singleton class"
end
def instance
instance_variable_get("@instance")
end
end
# test for singleton
class Test
include Singleton
end
a, b = Test.instance, Test.instance
puts a==b #=>true