Rlog

루비의 상속구조 본문

Ruby

루비의 상속구조

dev_roach 2021. 9. 28. 23:15
728x90

루비도 잘 알려진 객체지향 언어이다.

사실 최근에는 루비 온 레일즈라는 프레임워크를 아는 사람은 있어도, 이게 루비라는 언어로 이루어져 있다는 걸 모르는 사람도 보았다 😂

뭐 여튼 루비도 나름의 루비만의 장점이 있다.

서론은 뒤로 하고, 오늘은 루비가 어떻게 상속구조를 이루고 있는지 적어보려고 한다.

일단 보통언어와 비슷하게 루비도 아래와 같은 코드로 상속구조 표현이 가능하다.

class Bird

    def speak
        puts "tweet"
    end

end

class Duck < Bird

    def speak
        puts "quack"
    end

end

duck = Duck.new
duck.speak

위와 같이 적고 실행하게 되면 아래와 같은 결과가 나온다.

"quack"

당연해 보인다. Duck 안에 speak 가 있으니까, Bird 에 있는 speak 를 무시하고 실행하지..
더 깊게 설명하자면, 루비의 메소드를 찾는 방법은 ancestor 라는 배열을 이용한다.

그럼 Duck 의 현재 ancestor 배열을 보자.

print Duck.ancestors

[Duck, Bird, Object, Kernel, BasicObject]

BasicObject 부터 시작해서 커널을 거쳐 Object 까지..
루비는 이렇게 자신의 조상들을 배열로 가지고 있다. 그렇다면 우리의 speak 메소드는 어떻게 찾은걸까?
쉽다! 배열의 앞의 클래스에 저 메소드가 있는지 보는 것이다. 우선적으로 앞에 있는 것을 출력시켜주는 것이다.

그렇다면 만약 위와 같은 상황에서 Duck 의 speak 에서 "tweet" 을 내고 싶으면 어떻게 할까?
간단하다. 아래와 같이 super 를 사용해주면 된다.

class Bird

    def speak
        puts "tweet"
    end

end

class Duck < Bird

    def speak
        super
    end

end

duck = Duck.new
duck.speak

이젠 duck 에서도 tweet 이라고 잘 나온다.

자 이제 그렇다면 우리가 주로 쓰는 모듈의 prepand, include 에 대해서 알아보자.
Ruby 를 공부해봤다면 prepend 로 모듈을 가져오게 된다면, 클래스 보다도 우선순위가 높다.
우리는 위에서 한번 ancestor 의 배열을 봤기에 이게 어떻게 가능한지 추측할 수 있을 것 이다.

아마도 ancestor 의 배열에서 기존 클래스보다 앞선 위치에 자리할 것이다.

테스트를 한번 해보자.

module A
    def read
        "module A"
    end
end

module B
    def read
        "module B"
    end
end

class Test
    prepend A
    include B

    def read
        "Class Test!"
    end
end

위와 같은 식의 ancestor 는 무엇이 나올까?

[A, Test, B, Object, Kernel, BasicObject]

prepend 로 가져온 A는 위에서 우리가 예측한대로 Test 앞에 위치한다.
Include 는 Test 의 뒤에 위치한다. 즉 아까 클래스 상속과 같은 위치에 해당한다.

즉 Ruby 가 ancestors 라는 배열로 조상들을 관리하기에, 메세지를 이를 통해서 찾고 이러한 관리방식으로 인하여 prepend 와 include 를 이용할 수 있게 되었다!👍

'Ruby' 카테고리의 다른 글

Ruby Block, Proc, Lambda  (0) 2021.09.20