Singleton
Singleton
Singleton 모듈은 싱글턴(Singleton) 패턴을 구현해 주는 모듈이에요. 클래스에 include 하면 그 클래스의 인스턴스가 프로그램 전체에서 단 하나만 만들어지도록 보장해 줘요.
출처: Ruby 3.3 API
본문
사용법
Singleton을 쓰려면 클래스에 모듈을 include 하면 돼요.
class Klass
include Singleton
# ...
end
이렇게 하면 Klass의 인스턴스는 단 하나만 만들 수 있어요.
a,b = Klass.instance, Klass.instance
a == b
# => true
Klass.new
# => NoMethodError - new is private ...
인스턴스는 Klass.instance()를 처음 호출하는 순간에 만들어져요.
class OtherKlass
include Singleton
# ...
end
ObjectSpace.each_object(OtherKlass){}
# => 0
OtherKlass.instance
ObjectSpace.each_object(OtherKlass){}
# => 1
이런 동작은 상속과 클론(clone) 상황에서도 그대로 유지돼요.
동작 원리
위 결과는 다음 방법으로 얻어져요.
Klass.new와Klass.allocate를 private으로 만든다.Klass.inherited(sub_klass)와Klass.clone()을 오버라이드해서 상속·클론 시에도 싱글턴 속성이 유지되게 한다.Klass.instance()메서드를 제공해서 호출할 때마다 같은 객체를 돌려준다.Klass._load(str)을 오버라이드해Klass.instance()를 호출하게 한다.Klass#clone과Klass#dup을 오버라이드해TypeError를 던져 클로닝·듀핑을 막는다.
Singleton과 Marshal
기본적으로 Singleton의 _dump(depth)는 빈 문자열을 돌려줘요. 그래서 Marshal을 쓸 때 기본적으로 인스턴스 변수 같은 상태 정보가 빠져요. Singleton을 쓰는 클래스는 사용자 정의 _load(str)와 _dump(depth) 메서드를 제공해서 이전 상태 일부를 보존할 수 있어요.
require 'singleton'
class Example
include Singleton
attr_accessor :keep, :strip
def _dump(depth)
# this strips the @strip information from the instance
Marshal.dump(@keep, depth)
end
def self._load(str)
instance.keep = Marshal.load(str)
instance
end
end
a = Example.instance
a.keep = "keep this"
a.strip = "get rid of this"
stored_state = Marshal.dump(a)
a.keep = nil
a.strip = nil
b = Marshal.load(stored_state)
p a == b # => true
p a.keep # => "keep this"
p a.strip # => nil
Constants
VERSION
Public Class Methods
_load()
기본적으로 instance()를 호출해요. 싱글턴 상태를 보존하려면 오버라이드하면 돼요.
instance()
싱글턴 인스턴스를 돌려줘요.
Private Class Methods
append_features(mod)
모듈이나 클래스가 아닌 대상에 포함되면 TypeError를 던져요.
included(klass)
klass의 new와 allocate를 private 클래스 메서드로 만들고 SingletonClassMethods를 extend 해요.
Public Instance Methods
_dump(depth = -1)
기본적으로 marshal할 때 아무 상태도 보존하지 않아요.
clone()
클로닝을 막기 위해 TypeError를 던져요.
dup()
듀핑을 막기 위해 TypeError를 던져요.