
Ruby 单例模式讲解和代码示例
单例是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。
单例拥有与全局变量相同的优缺点。 尽管它们非常有用, 但却会破坏代码的模块化特性。
在某些其他上下文中, 你不能使用依赖于单例的类。 你也将必须使用单例类。 绝大多数情况下, 该限制会在创建单元测试时出现。
复杂度:
流行度:
使用示例: 许多开发者将单例模式视为一种反模式。 因此它在 Ruby 代码中的使用频率正在逐步减少。
识别方法: 单例可以通过返回相同缓存对象的静态构建方法来识别。
基础单例
实现一个粗糙的单例非常简单。 你仅需隐藏构造函数并实现一个静态的构建方法即可。
相同的类在多线程环境中会出错。 多线程可能会同时调用构建方法并获取多个单例类的实例。
main.rb: 概念示例
# The Singleton class defines the `instance` method that lets clients access the
# unique singleton instance.
class Singleton
@instance = new
private_class_method :new
# The static method that controls the access to the singleton instance.
#
# This implementation let you subclass the Singleton class while keeping just
# one instance of each subclass around.
def self.instance
@instance
end
# Finally, any singleton should define some business logic, which can be
# executed on its instance.
def some_business_logic
# ...
end
end
# The client code.
s1 = Singleton.instance
s2 = Singleton.instance
if s1.equal?(s2)
print 'Singleton works, both variables contain the same instance.'
else
print 'Singleton failed, variables contain different instances.'
end
output.txt: 执行结果
Singleton works, both variables contain the same instance.
线程安全单例
为了解决这个问题, 你必须在创建首个单例对象时对线程进行同步。
main.rb: 概念示例
# The Singleton class defines the `intance` method that lets clients access the
# unique singleton instance.
class Singleton
attr_reader :value
@instance_mutex = Mutex.new
private_class_method :new
def initialize(value)
@value = value
end
# The static method that controls the access to the singleton instance.
#
# This implementation let you subclass the Singleton class while keeping just
# one instance of each subclass around.
def self.instance(value)
return @instance if @instance
@instance_mutex.synchronize do
@instance ||= new(value)
end
@instance
end
# Finally, any singleton should define some business logic, which can be
# executed on its instance.
def some_business_logic
# ...
end
end
# @param [String] value
def test_singleton(value)
singleton = Singleton.instance(value)
puts singleton.value
end
# The client code.
puts "If you see the same value, then singleton was reused (yay!)\n"\
"If you see different values, then 2 singletons were created (booo!!)\n\n"\
"RESULT:\n\n"
process1 = Thread.new { test_singleton('FOO') }
process2 = Thread.new { test_singleton('BAR') }
process1.join
process2.join
output.txt: 执行结果
If you see the same value, then singleton was reused (yay!)
If you see different values, then 2 singletons were created (booo!!)
RESULT:
FOO
FOO