Singleton method는 특정 인스턴스에만 생성되는 메소드를 뜻합니다. 예를 들면,
irb(main):001:0> class Foo; end => nil irb(main):002:0> a = Foo.new => #<Foo:0x2c6d2b0> irb(main):003:0> b = Foo.new => #<Foo:0x2c6ad60> irb(main):004:0> class << a irb(main):005:1> def bar irb(main):006:2> puts "hi" irb(main):007:2> end irb(main):008:1> end => nil irb(main):009:0> a.bar hi => nil irb(main):010:0> b.bar NoMethodError: undefined method `bar' for #<Foo:0x2c6ad60> from (irb):10
와 같이 a라는 인스턴스에는 메소드를 만들되, b라는 인스턴스에는 메소드를 만들지 않는 것이 singleton method입니다. 이것의 실례는 맨 앞의 링크에 나와있듯이 소켓통신 하는 프로그램입니다. 만약 다음과 같이 소켓을 sever.accept에서 받으면서 받은 소켓을 즉시 Pop3Server라는 모듈을 extend하게 한다고 해보죠.
while (session = server.accept) session.extend Pop3Server Thread.new(session) do |s| s.run end end
그러면
module Pop3Server def run // 여기서는 소켓의 메소드들을 직접 접근 가능. // 즉, @sock.print 와 같이 인자로 받은 @sock을 접근하게 하는게 아니라 // 곧바로 print를 호출하면 이것이 socket클래스 인스턴스의 메소드를 접근하게 됨 end end
위 주석에 나와있듯이 소켓의 모든 메소드를 접근하는 run메소드를 편리하게 추가할 수 있죠.
하지만, 싱글톤 메소드는 싱글톤이므로 이의 복제를 만드는 것은 불가능합니다. 안그러면 ‘싱글톤’이 아니겠죠. 이는 또다른 문제를 야기할 수 있습니다. 다음과 같이 String클래스에 싱글톤 메소드를 생성했다고 하겠습니다.
irb(main):001:0> s = "foobar" => "foobar" irb(main):002:0> class << s irb(main):003:1> def hi irb(main):004:2> puts "hi" irb(main):005:2> irb(main):006:2* end irb(main):007:1> end => nil
다음, s.upcase를 호출하게 되면?
irb(main):012:0> s2 = s.upcase => "FOOBAR" irb(main):013:0> s2.hi NoMethodError: undefined method `hi' for "FOOBAR":String from (irb):13 irb(main):014:0> s.hi hi => nil
이와같이 미처 생각지도 못하게 hi 라는 메소드를 잃어버리게 됩니다.