[루비 사용자 가이드] 상속

루비/레일스 프로그래밍/루비 사용자 가이드 2007.05.06 17:29

일상 생활에서 사물을 분류할 때는 자연스럽게 계층적으로 하게 됩니다. 우리는 모든 고양이가 포유류라는 것과 모든 포유류는 동물이라는 것을 압니다. 작은 클래스는 그들이 속한 더 큰 클래스루부터 특성을 상속(inherit)받습니다. 만약 모든 포유류가 숨을 쉰다면, 모든 고양이도 숨을 쉽니다.

이런 개념을 루비에서는 다음과 같이 씁니다:

ruby> class Mammal
    |   def breathe
    |     puts "inhale and exhale"
    |   end
    | end
   nil
ruby> class Cat<Mammal
    |   def speak
    |     puts "Meow"
    |   end
    | end
   nil

Cat이 어떻게 숨을 쉬어야 할지를 정확히 지정하지 않았지만, 모든 고양이는 그 행동을 Mammal로부터 상속받게 됩니다. 왜냐하면 CatMammal의 하위클래스로 지정되었기 때문입니다( 객체지향 용어로 더 작은 클래스는 하위클래스(subclass)이고 더 큰 클래스는 상위클래스(superclass)라고 합니다.) 프로그래머의 입장에서 보면 고양이는 숨을 쉴 수 있는 능력을 공짜로 얻는 셈입니다. speak 메소드를 추가하면 고양이는 숨도 쉬고 말도 할 수 있습니다.

ruby> tama = Cat.new
   #<Cat:0xbd80e8>
ruby> tama.breathe
inhale and exhale
   nil
ruby> tama.speak
Meow
   nil

상위 클래스의 몇몇 특성을 하위 클래스가 상속해지 말아야만 하는 경우도 있을 것입니다. 일반적으로 새는 날 수 있지만, 팽귄은 새면서도 날 수 없습니다.

ruby> class Bird
    |   def preen
    |     puts "I am cleaning my feathers."
    |   end
    |   def fly
    |     puts "I am flying."
    |   end
    | end
   nil
ruby> class Penguin<Bird
    |   def fly
    |     fail "Sorry. I'd rather swim."
    |   end
    | end
   nil

우리는 모든 새로운 클래스의 특성을 일일히 정의하지 않고, 상위 클래스와 하위 클래스간의 차이만을 다시 정의하거나 추가하면 됩니다. 이렇게 상속을 사용하는 것을 때때로 차이를 이용한 프로그래밍(differential programming)이라고 부르기도 합니다. 이런 식으로 객체의 클래스를 정의할 수 있는 것은 객체지향의 중요한 잇점 중 하나입니다.


신고
Trackback 0 : Comment 0

[루비 사용자 가이드] 클래스

루비/레일스 프로그래밍/루비 사용자 가이드 2007.05.02 20:17

실제 세계는 물체(객체,Object)로 가득차 있습니다. 그리고 그 객체를 분류할 수 있습니다. 예를 들어 아기들은 개를 보면 그 품종과 상관 없이 "멍멍"하고 말합니다. 인간은 선천적으로 세상을 이런 구분을 지으면서 바라봅니다.

객체지향 프로그래밍 용어로 "개"와 같은 객체의 종류를 클래스(class)라 합니다. 그리고 어떤 클래스에 속한 특정 객체를 그 클래스의 인스턴스(instance)라고 합니다.

일반적으로 루비나 다른 객체지향 언어에서 객체를 만들 때는, 먼저 클래스의 특성을 정의하고, 그 다음에 그 클래스의 인스턴스를 만듭니다. 이 과정을 보여주기 위한 첫 예로 Dog 클래스를 정의해 봅시다.

ruby> class Dog
    |   def speak
    |     puts "Bow Wow"
    |   end
    | end
   nil

루비에서 클래스 정의는 키워드 classend 사이에 있는 코드 영역입니다. 그 영역 안의 def는 클래스의 메소드를 정의합니다. 앞의 글에서 살펴본 것 처럼, 메소드는 클래스에 속하는 객체의 구체적인 행동 방식에 해당합니다.

Dog 클래스를 정의했으니까, 개 객체를 하나 만들어 봅시다:

ruby> pochi = Dog.new
   #<Dog:0xbcb90>

우리는 Dog 클래스의 인스턴스를 하나 만들었습니다. 그리고, 그 객체에 pochi라는 이름을 붙였습니다. 어떤 클래스던 new 메소드는 그 클래스의 인스턴스인 객체를 새로 생성합니다. pochiDog의 객체이기 때문에, 앞에서 말한 클래스의 정의에 따라서, Dog가 가져야 한다고 정한 모든 특성을 부여받습니다. 앞에서 정의한 Dog의 특성은 매우 단순했습니다. 따라서 우리가 pochi에게 시킬 수 있는 동작은 다음 한 가지 뿐입니다.

ruby> pochi.speak
Bow Wow
   nil

어떤 클래스의 새 인스턴스를 만드는 것을 다른 말로는 클래스의 인스턴스화(instantiation)라고 합니다. 개와 이야기 하는 기쁨을 맛보려면 개가 한마리 있어야 합니다. 마찬가지로 Dog class에게 우리를 위해 짖으라는 요청을 할 수는 없습니다.

ruby> Dog.speak
ERR: (eval):1: undefined method `speak' for Dog:class

이것은 샌드위치라는 개념을 먹는 것이 아무 의미가 없는 것과 마찬가지입니다.

반면 특정 개에 이름을 붙이지 않고 개의 짖는 소리를 듣고 싶다면 순간적인 임시의 개를 생성할 수 있고, 그 개가 사라지기 전에 짓도록 명령할 수 있습니다.

ruby> (Dog.new).speak   # 보통 Dog.new.speak라고 더 많이 씀
Bow Wow
   nil

"잠깐": 의문이 들 수 있습니다. "나중에 사라지다니, 이 불쌍한 개에게 무슨 일이 벌어진거지?" 맞습니다. 만약 우리가 이름을 부여하지 않으면(pochi에게 했던 것 같이 말이죠), 루비의 자동화된 가비지 컬렉션이 그 개가 필요 없는 버려진 개라고 생각하고, 사정없이 그 객체를 없애버립니다. 여러분도 아시겠지만, 원하는 개를 항상 만들 수 있기 때문에 실제로는 아무런 문제가 없습니다.


신고
Trackback 1 : Comment 0

티스토리 툴바