Ruby는 다중 상속을 지원하지 않는다.
즉 Ruby 클래스는 하나의 부모 클래스(슈퍼 클래스)만 가질 수 있다는 뜻이다.
Ruby에서는 다중 상속을 모듈의 Mixin을 통해 구현이 가능하다.
Mixin에 대해 알아보기 전 Class와 Module의 차이점과 클래스 조상의 목록인 Ancestors에 대해 먼저 확인해보자.
Class vs Module
Class
객체 지향 프로그래밍에서 클래스는 클래스 인스턴스, 클래스 객체, 인스턴스 객체 또는 간단히 객체라고 하는 자체 인스턴스를 만드는 데 사용되는 구성이다.
클래스는 인스턴스가 상태와 동작을 가질 수 있도록 하는 구성 요소를 정의한다.
따라서 클래스는 객체 생성을 위해 만드는 것이다.
Module
루비에서 모듈은 “메서드와 상수의 모음”을 뜻한다.
따라서 모듈은 여러 클래스에서 사용할 수 있는 메서드를 제공하기 위해 만드는 것이다.
정리하자면, 클래스는 객체에 관한 것이며 모듈은 기능에 관한 것이다.
모듈은 클래스와 다르게 인스턴스를 생성할 수 없다.
모듈의 주 목적은 그 안에 정의한 메서드를 다양한 클래스에 include, prepend, extend를 통해 mixin 해서 재사용하는 것이다.
Ancestors
루비에서는 클래스가 생성될 때 ancestors 배열에 클래스 조상의 목록을 저장해둔다.
ancestors에는 이 클래스가 상속받는 모든 클래스, 자기 자신, 그리고 mixin된 모듈들이 포함된다.
String.ancestors
# => [String, Comparable, Object, Kernel, BasicObject]
클래스의 인스턴스 메서드를 호출하면, ancestors 배열의 앞에서부터 메서드 정의를 찾는다.
Mixin
include
클래스의 인스턴스 메서드를 확장하여 모듈의 메서드를 사용할 수 있도록 한다.
include를 사용할 경우 해당 모듈은 원 클래스보다는 낮고 부모 클래스보다는 높은 우선순위를 가지게 된다.
module LogModule
def log
puts "log by LogModule"
end
end
class BaseClass
def log
puts "log by BaseClass"
end
end
class ServiceClass < BaseClass
include LogModule
end
ancestors 배열을 확인해보면 MyModule이 원클래스인 MyClass의 뒤에 그리고 부모 클래스인 BaseClass보다는 앞에 위치해 있는 것을 볼 수 있다.
ServiceClass.ancestors
# => [ServiceClass, LogModule, BaseClass, Object, Kernel, BasicObject]
prepend
클래스의 인스턴스 메서드를 확장하여 모듈의 메서드를 사용할 수 있도록 한다.
include와 다르게 prepend를 사용할 경우 해당 모듈은 원 클래스보다도 높은 우선순위를 가지게 된다.
즉, 클래스의 기존 메서드를 꾸며주는 역할을 한다.
아래와 같이 super 키워드를 조합하면 기존 메서드 앞이나 뒤에 원하는 동작을 추가할 수 있다.
module LogModule
def log(agrs)
puts "=== start loggging by LogModule ==="
puts super # ServiceClass의 log 호출
puts "=== finish loggging by LogModule ==="
end
end
class ServiceClass
prepend LogModule
def log(args)
args.inspect
end
end
ancestors 배열을 확인해보면 MyModule이 원클래스인 MyClass보다도 앞에 위치해 있는 것을 볼 수 있다.
extend
위에서 본 include, prepend와 다르게 extend를 사용할 경우
클래스의 클래스 메서드를 확장하여 모듈의 메서드를 사용할 수 있도록 한다.
module LogModule
def log
"log by LogModule"
end
end
class ServiceClass
extend LogModule
end
ServiceClass.log
# => log by LogModule
extend는 클래스 메서드를 확장하기 때문에 클래스 메서드가 정의되는 싱글톤 클래스의 ancestors에서 MyModule을 확인할 수 있다.
ServiceClass.singleton_class
# => #<Class:ServiceClass>
ServiceClass.singleton_class.ancestors
# => [#<Class:ServiceClass>, LogModule, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]
<참고>
https://matt.aimonetti.net/posts/2012-07-ruby-class-module-mixins/
'Programming > Ruby On Rails' 카테고리의 다른 글
[Ruby On Rails] database migration 관련 명령어 모음 (0) | 2023.05.18 |
---|---|
[Ruby On Rails] Module Mixin (2) - ActiveSupport::Concern (0) | 2023.04.30 |
[Ruby On Rails] Eager loading으로 N+1 문제 해결하기 (0) | 2023.04.16 |
[Ruby On Rails] Elasticsearch 검색 템플릿(Search Template) 사용하기 (0) | 2023.03.28 |
[Ruby On Rails] enum 경고 문구 - Overwriting existing method (0) | 2023.03.26 |