Post

상속, 인터페이스, 트레이트 차이점과 어떨 때 사용하나.

상속, 인터페이스, 트레이트의 차이

상속과 나머지 두 관계의 가장 큰 차이점은, 인터페이스와 트레이트는 기능 단위 라는 것이다. 그래서 클래스 사이에 연관 관계가 없어도 기능 단위의 공통점을 가지도록 할 수 있다.

abstract

추상 클래스를 사용하려면 extends를 사용해야 하므로, 상속 계층에 연결된다. 추상 클래스는 반드시 하나 이상의 추상 메소드를 포함해야 한다. 추상 메소드는 하위 클래스에서 반드시 재정의되어야 한다. interface와 달리 일반 메소드도 포함할 수 있다. 상속 계층을 먹고 들어간다는 점, 메소드 재정의 강제는 interface로도 가능하다는 점 때문에 신중하게 써야한다.

interface

인터페이스에 어떤 메서드가 있는지 알고 있다면, 각 클래스에서 인터페이스를 어떻게 구현했는지는 신경 쓸 필요 없이 그냥 호출하면 된다. 파라미터 타입으로 인터페이스를 적으면, 기능 단위 공통점을 제외하면 서로 연관 관계가 없는 클래스들을 모두 받을 수 있다.

trait

상속과 달리 여러 개를 Mixin할 수 있으며 인터페이스와 달리 구현부를 가질 수 있다. 그래서 상속과 인터페이스의 중간 쯤으로 생각할 수 있으나, 기능 단위라는 점에서 인터페이스에 더 가까운 듯.

이러한 성격 때문에,

인터페이스는 각 클래스 마다 각자의 사정에 맞게 구현해 내부 처리가 모두 다를 때 사용하고

트레이트는 모든 클래스에서 구현이 동일해야 할 때 사용한다.

단일 상속 모델은 기본적인 구현을 제공하는 일반화된 하나의 루트 클래스에서 시작해서 이 루트 클래스를 확장해 나가면서 바로 윗 부모의 구현을 상속받아 좀 더 특화된 클래스를 생성하게 된다.

이를 상속 계층이라 부른다. 이러한 상속 계층은 대부분의 경우 잘 동작하지만 연관이 없는 두 클래스가 유사한 속성을 갖도록 해야 하는 경우 문제가 발생한다. 예를 들어 CarRetailStore는 상속 계층상 공통의 부모를 공유하지 않지만, 두 클래스 모두 지도 위에 표시될 위치정보를 나타낼 수 있어야 한다. 트레이트는 이러한 목적을 위해 사용된다. 즉, 트레이트는 모듈화된 구현을 서로 관련 없는 클래스들에 주입하기 위해 사용한다. 새로운 부모 클래스를 상속? → 기존 상속 계층을 깨트리기 때문에 당연히 부자연스럽다. 인터페이스를 구현? → CarRetailStore에 같은 구현이 중복된다. 이는 DRY 하지 않다. 트레이트를 사용하면 상속 계층을 깨트리지 않으면서 구현은 중복하지 않을 수 있다. * 이럴거면 다중 상속을 지원하면 되는거 아닌가? 싶지만 클래스 상속과 트레이트 사용은 상기했듯이 그 의미가 다르다. 상속은 상속 계층을 따라 좀 더 부모와 직접적인 관련이 있는 느낌, 부모를 좀 더 구체화해서 구현하는 느낌이다. 어떤 클래스를 상속한다는 것은 그 클래스를 근간으로 한다는 것을 의미한다. 반면 트레이트는 모듈화된 구현을 가져다 쓰는 import의 느낌, 단순한 기능 추가의 느낌이 강하다.

This post is licensed under CC BY 4.0 by the author.