Singleton class
곡갱이 책 의 원저자 Dave Thomas가 자신의 루비 강좌에서 냈던 Quiz를 하나 소개 했습니다.
문제
아래 코드에서 say_hello 를 호출할 수 있을까요? 몇 가지 방법이나 있을까요?
class Fred
class << self
class << self
def say_hello
puts "Hi!"
end
end
end
end
만약 위 문제의 답을 모르는 분이 계시다면 아마 틀림없이 ‘class << Fred’ 부분을 잘 이해하지 못해서일 것입니다.
우리는 여기서 ‘<<’ 을 유심히 봐야 합니다. 루비에서 클래스 상속을 할 때, ‘class Man < Person’ 처럼 ‘<’를 사용합니다. 그런데 ‘<<’는 singleton class (여기서는 Fred의 singleton class)라고 하는 전혀 다른 의미의 상속 관계를 의미합니다.
지금부터, Singleton class에 대해서 한 번 설명해보려고 합니다. 내용이 길고 중간중간 난폭 혹은 졸음 설명도 있을 수 있으므로, 그래도 이번 기회에 singleton에 대해서 꼭 이해해보겠다는 분들은 안전벨트 단단히 메고 계속 읽어주세요. 아! 그리고 디자인패턴에서 말하는 singleton은 잠시 잊어주세요.
‘<<’ 와 ‘<’의 4가지 차이점
위에서 Singleton Class를 표시하는 ‘<<’이 전혀 다른 의미의 상속을 표현한다고 구체적으로 무엇이 다를까요? 크게 네 가지가 다릅니다.
이름이 없다.
우선, ‘class << X’ 에 의해서 만들어지는 X의 singleton class는 자기만의 이름이 없습니다. 그 이유는, X의 singleton class는 딱 하나만 존재할 수 있기 때문입니다. 하나만 존재할 수 있는데 굳이 이름을 붙일 이유가 없겠죠.
instance 를 만들 수 없다.
둘째, singlteton class는 instance object를 마음대로 만들 수 없습니다.(즉 new를 할 수 없습니다.) X의 singleton class의 유일한 instance object 는 X입니다. 이것은 singleton class가 만들어지는 순간부터 자동으로 정해지는 불변의 사항입니다.
상속 방향이 반대다.
셋째, 일반적으로 ‘class A < B’와 같은 상속에서 만들어지는 클래스 A는 B의 child class로서 B의 성질(method들과 attribute들)을 물려받습니다. 그런데 ‘class << X’ 에서 만들어지는 X의 singleton class는 X의 성질을 물려받지 않습니다. 오히려, X가 자신의 singleton class의 성질을 물려받습니다. 즉, X의 singleton class에서 method1()을 정의했다면 X는 method1을 상속받게 되고, X.method1() 과 같이 호출하는 것이 가능합니다.
Class가 아닌 Object 에 대해서도 적용된다.
끝으로 ‘<’를 이용한 상속은 클래스대 클래스간에만 가능합니다. 즉 ‘class A < B’ 에서 A와 B는 반드시 클래스이어야 합니다. 그런데 ‘class << X’ 에서 X는 꼭 클래스가 아니어도 됩니다. Object이기만 하면 됩니다. 즉, a = ‘abc’ 라고 할 때, ‘class << a’ 와 같은 것이 가능합니다. 이 때, a는 String 클래스의 하나의 instance object입니다. 그런데 만약 ‘class << a’ 즉 a의 singleton class에 print_first_char 같은 method를 정의한다면 이 method는 a에 상속이 되므로 a.print_first_char 와 같은 호출이 가능합니다. 그렇지만, “xy”와 같은 다른 Stirng의 instance들에서는 전혀 사용할 수 없습니다.
Singleton Class 와 class method
그러면, Singleton class는 왜 존재할까요? 루비를 조금 아시는 분들 중에 나는 아직 한 번도 써본 적이 없다고 생각하시는 분들도 사실은 자신도 모르는 사이에 많이 사용하고 계셨을 겁니다. 그 것은 바로 class method 때문입니다.
X라는 class의 class method 는 C++에서의 static member funtion 과 같이 클래스 자체에 대해서만 호출 할 수 있고, 그 클래스의 instance에 대해서는 호출할 수 없는 method입니다. 그런데 ruby에서는 이 class method를 singleton class를 이용해서 구현합니다. 즉,
class Fred
def Fred.laugh
puts ' hahah'
end
end
와
class Fred
def self.laugh
puts ' hahah'
end
end
의 두 가지 코드는 대부분이 아시겠지만 동일한 코드로, Fred의 class method인 laugh를 정의하고 있습니다. 그런데 이 코드는 사실 아래의 코드에 대한 편리한 문법적 허용(syntax sugar, 문법 사탕)이라고 할 수 있습니다.
class << Fred
def laugh
puts ' hahah'
end
end
그런데 이 코드는 아래처럼 ‘class Fred’와 ‘end’ 사이에 들어가도 여전히 동일합니다.
class Fred
class << Fred
def laugh
puts ' hahah'
end
end
end
그런데 ‘class Fred’ 와 ‘end’ 사이에서 ‘self’는 ‘Fred’를 의미하기 때문에 위의 코드는 아래의 코드와 다시 같아집니다.
class Fred
class << self
def laugh
puts ' hahah'
end
end
end
아시겠습니까. 위의 코드는 단순히 Fred의 class method인 laugh를 정의하는 코드이고, 이 때 laugh는 Fred.laugh 와 같이 호출하면 됩니다.
문제 해결
그럼 이제 Dave의 문제를 다시 한번 볼까요?
class Fred
class << self
class << self
def say_hello
puts "Hi!"
end
end
end
end
Dave는 문제를 한 번 더 꼬아두었습니다. 즉 class << self 가 한 번 더 있습니다. 천천히 생각해봅시다. 먼저 앞에서 설명한 바에 따르면 위의 코드는 아래와 같은 코드가 됩니다.
class << Fred
class << self
def say_hello
puts 'Hi'
end
end
즉 say_hello는 ‘Fred의 Singleton Class’의 Singleton class의 method입니다. ‘X의 singleton class의 method’는 X에 상속되므로 또한 ‘X 의 method’라는 사실을 잊지마세요. 여기서 X의 method라는 것은 X.method처럼 호출할 수 있다는 것이므로 만약 X가 클래스라면 X의 class method가 됩니다. 문제에 적용보면 X = ‘Fred의 Singleton Class’가 되므로 say_hello는 ‘Fred의 Singleton Class’의 class method가 됩니다.
보통 class의 상속에서도 그렇듯이 Fred는 자신의 Singleton class의 일반 method들은 상속받지만 class method는 상속받지 않습니다. 따라서 say_hello는 Fred의 method가 아닙니다.
따라서 say_hello의 호출은 Fred의 Singleton Class에서만 할 수 있습니다. 만약 Fred의 Singleton Class가 이름 이름이라도 있다면, 예를 들어 Fred_Singleton 이라면 Fred_Singleton.say_hello 라고 할 수 있겠죠. 하지만 서두에 밝혔듯이 Singleton class에는 이름이 없습니다.
방법은 무엇일까요? 바로 Singtone Class 내부로 들어가는 것입니다. ‘class << Fred’ 와 ‘end’ 사이에서 ‘self’는 바로 Fred의 singleton class 를 의미합니다. 따라서,
class << Fred
self.say_hello
end
와 같이 하면 say_hello 가 호출됩니다.
그런데 여기서 self는 생략할 수 있습니다. (어떤 method를 호출할 때 그 method를 수행할 객체 즉 receiver를 지정하지 않으면 현재 name space의 self 를 receiver로 간주합니다.)
따라서 위의 코드는 아래와 같이 써도 무방합니다.
class << Fred
say_hello
end
이것을 한 줄로 줄이면 아래와 같이 됩니다.
class << Fred; say_hello end
마침
와 설명이 상당히 길어졌군요. 혹시 여기까지 다 읽으신 분이 있다면 대단하십니다. 이렇게 별 재미없는 글을 여기까지… 저 같으면 읽지 않습니다. ^^
사실 Singleton은 다른 언어에 없는 개념이라서 처음에는 다소 이해하기 힘든 것 같습니다. 지난 루비세미나에서 대산님이 이 개념을 짧고 명쾌하게 한 번 설명하신 적이 있었습니다. 갑자기 다른 얘기지만 이런 분이 직접 써서 최근에 출간된 웹 개발 2.0 루비 온 레일스 는 얼마나 쉽게 잘 설명되어 있을까 싶네요
Comments
-
iizeqcfeldumnfjvguxzerlfdizkit by tutjsz
-
희귀한 자원인가바여.
-
잘 읽었습니다. 쉽고 재밌고 유익한 설명 감사드립니다. ^_^ by nainu
-
음. 옛날글인데 스팸 댓글이.. 초간단 휴먼형 스팸 필터라 잘 뚤리네 ㅎㅎ
-
스팸 좋네요.. 예전 글을 다시 끄집어서 읽게 만들어주는.. good job! :)
-
wlmauwvtbouucsbhvzthabtmdgpwid by fhyaqp
-
I know some <a href=http://www.wowgoldshopping.com>wow gold</a> in wow,i love wow,love <a href=http://www.wowgold-shopping.com>wow gold</a>,love wowgoldshopping.com,too. by wow gold
-
I know some <a href=http://www.wowgoldshopping.com>wow gold</a> in wow,i love wow,love <a href=http://www.wowgold-shopping.com>wow gold</a>,love wowgoldshopping.com,too. by wow gold
-
【奇天卫视】卫星电视器材专售!中星9号套站大量到货。DM500套餐特价销售。欢迎访问www.cnsatv.com 电话13092168168 !淘宝超级大卖家!可以通过支付宝交易,也可以办理货到付款业务。 淘宝网店地址shop33792895.taobao.com/ <p><a href=“http://www.cnsatv.com”><font color=“#0000FF”>www.cnsatv.com</font></a></p> by cnsatv