사용 사례들: 많은 개발자는 싱클턴을 안티패턴으로 간주합니다. 그래서 루비 코드에서의 사용이 감소하고 있습니다.
식별: 싱글턴은 같은 캐싱 된 객체를 반환하는 정적 생성 메서드로 식별될 수 있습니다.
기본 싱글턴
조잡한 싱글턴을 구현하는 것은 매우 쉽습니다. 생성자를 숨기고 정적 생성 메서드를 구현하기만 하면 됩니다.
같은 클래스는 다중 스레드 환경에서 잘못 작동합니다. 여러 스레드가 생성 메서드를 동시에 호출할 수 있으며 싱글턴 클래스의 여러 인스턴스를 가져올 수 있기 때문입니다.
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