루비만의 모듈 사용 방법이다. 이 방법을 이용하면 다중 상속 문제나 굳이 상속을 할 필요가 사라진다.
루비는 단일 상속을 지원하는 언어이고 믹스인을 통해 다중 상속을 간접적으로 지원한다.
1. 그렇다면 상속이 아닌 왜 믹스인을 써야 할까?
정답은 상황에 따라 다르다.
상속을 사용해야 하는 상황은 리스코프의 치환 원칙으로 설명할 수 있다.
이 원칙은 "타입 T 객체 x에 관해 참이 되는 속성을 q(x)라고 한다면, S가 T의 자식이라면 타입 S의 객체 y에 대해 q(y)도 참이 된다."로 설명할 수 있다.
즉, 부모 클래스의 객체는 모두 자식 클래스의 객체로 바꿔서 사용할 수 있고 자식 클래스는 한 종류의 부모 클래스라고 말할 수 있어야 한다는 의미다.(is-a)
ex) 자동차는 운송 수단이다.
즉, is-a관계에 있다면 상속을 사용하는 것을 권장한다.
그런데 여기서 문제가 상속을 사용하면 강한 결합을 만들어 낸다.
한 예로, 자식 클래스에서 부모 클래스에 정의된 메서드를 사용하고 있다면, 부모 클래스의 수정으로 자식 클래스에 문제가 생길 여지가 존재한다.
그래서 is-a관계에 있지 않다면 믹스인을 사용하는 것을 권장한다.
2. 사용 방법
class Array
include Enumerable
...
..
end
module Enumerable
def each_slice(n)
block_given? ? (yield to_a; nil) : [to_a].to_enum
end
end
실제 루비 Array 클래스가 Enumerable 모듈을 믹스인하고 있는 코드이다.
여기에서 block_given? 메서드는 ruby kernel 모듈이 제공하는 메서드다.
yield는 블록 문을 실행시키는 예약어다.
to_a는 리스트이고 each_slice에서 n크기만큼 자른 sublist를 반환한다.
블록에 sublist를 모두 yield문으로 실행시킨 후 nil을 최종적으로 반환한다.
만약에 블록이 없다면 enumerator 타입으로 서브 리스트를 가진 리스트를 반환한다.
여기서 (yield to_a; nil)을 이해하려면 삼항 연산자 특징을 알아야 한다. 조건식이 true일 때, 맨 마지막 값을 리턴해준다.
즉, block_given? ? (yield to_a; nil; 2; 5) : .. 라고 한다면, yield문이 끝난 후 5를 마지막에 리턴해준다.
list = [1,2,3]
list.each_slice(2) { |sub| p sub }
'ruby' 카테고리의 다른 글
DI(Dependency Injection) (0) | 2021.12.30 |
---|---|
instance variable encapsulation (0) | 2021.12.30 |
블록 (0) | 2021.12.26 |
루비에서 람다식이란 (0) | 2021.12.26 |
ruby 특징 (0) | 2021.12.26 |