스칼라 객체의 Traits(트레이트)와 Abstract Class(추상 클래스)

View: 204 0 0
작성자: 달빛제이크
카테고리: Scala Language
발행: 2024-05-26 수정 2024-06-21

안녕하세요. 달빛제이크입니다.

스칼라의 객체 지향에 대해서 설명을 이어가겠습니다.

3. Traits(트레이트)와 Abstract Class(추상 클래스)

먼저 다중 상속에 대해서 설명을 드리면, 전통적인 다중 상속이란 한 클래스가 두 개 이상의 부모 클래스로부터 상속을 받는 개념을 의미합니다.

C++에서 사용되며, 자식 클래스가 여러 부모 클래스의 속성과 메소드를 모두 물려받게 됩니다.

문제는 여러 부모 클래스로 부터 모든 속성과 메소드를 물려 받으니 강력하긴 하지만, 동일한 상위 클래스를 상속 받은 부모 클래스들을 동시에 상속 받을 경우, 그 동일한 상위 클래스를 여러 번 상속 받게 되는 다이아몬드 문제가 발생할 수 있고, 상속 받은 메소드, 속성의 이름이 겹칠 때, 이를 관리하고 해결하는 것이 복잡하게 됩니다.

이를 해결하기 위해 스칼라는 Java에서처럼 단일 상속을 채용하되, 다중 상속의 장점을 취하고자 Trait (트레이트)를 Mix-in (혼합)하여 사용합니다.

  • Trait (트레이트)

스칼라의 Trait는 extends와 with 키워드를 사용해서 mix-in 하며, 크게 2가지 용도로 사용할 수 있습니다.

첫 번째는 Java의 Interface를 대체하는 용도로 사용합니다.

트레이트는 클래스 처럼 필드와 메소드를 구체적으로 구현할 수 있지만, 추상 필드와 추상 메소드로도 구성할 수 있기 때문에 Java의 Interface 용도로 활용되고 있습니다. Interface가 객체 지향 프로그래밍에 있어서 매우 중요한 역할을 수행하기 때문에 Trait를 통해 이러한 구현 방식을 이어가고 있습니다.

두 번째는 method를 구현해서 특정한 기능을 부여하고 여러 개의 Trait를 mix-in 해서 Rich Interface를 만드는 데 사용합니다.

스칼라에서는 Trait에 대해서 상속이라는 표현을 쓰지 않고 mix-in (혼합)이라는 표현을 사용합니다. 이는 다중 상속과 차별화 하기 위한 용어로 생각되며, Trait의 기능적인 역할과 다중 상속에서 다이아몬드 문제에 대한 Solution을 제공한다는 측면에서 의미가 있습니다.

Rich Interface란 객체 지향 설계에 있어서 Interface의 설계 원칙을 설명하는 두 가지 개념 중 하나로 Thin Interface에 대립되는 개념입니다. 즉, 다양한 기능의 method를 많이 구현해서 사용자가 필요한 기능을 직접 구현할 필요 없이 바로바로 호출해서 사용할 수 있도록 설계한 Interface를 의미합니다. concrete method로 구현된 trait를 mix-in 하면 코드의 재사용성을 높이면서 손쉽게 Rich Interface를 만들 수 있습니다.

Trait의 Linearlization(선형화)으로 다중 상속의 다이아몬드 문제를 효과적으로 해결합니다.

Scala에서는 mix-in 된 Trait에 대해 처리 순서를 결정하여 super에 해당하는 상위 method를 명확하게 지정해 주고 중복을 해결합니다.

// Trait linearlization 예제
trait A {
  def message: String = "A"
}

trait B extends A {
  override def message: String = super.message + " B"
}

trait C extends A {
  override def message: String = super.message + " C"
}

class D extends B with C {
  override def message: String = super.message + " D"
}

val d = new D
println(d.message)  // "A B C D"

앞의 예제에서 Class D를 인스턴스 객체로 만들게 되면 D가 상속한 Trait B와 C 중 가장 나중에 mix-in한 Trait C가 먼저 실행이 되고 이어서 B가 실행이 됩니다. B와 C의 상위 Trait인 A는 가장 나중에 실행이 되어 d.message를 출력하게 되면 "A B C D"의 순서로 출력 됩니다.

  • Abstract Class (추상 클래스)

Scala에서는 추상 클래스를 지원합니다.

트레이트와 추상 클래스 모두 객체 지향 프로그래밍에 있어서 중요한 구성요소로 내부에 추상 필드와 추상 메소드를 다룰 수 있는 공통점이 있으나 트레이트는 mix-in을 통해 다중 상속 기능을 제공하고 있는 반면, 추상 클래스는 한 클래스에 하나의 추상 클래스만 상속 할 수 있습니다.

이와 같은 특징으로 인해서 트레이트는 다중 상속 mix-in에 대한 장점을 바탕으로, 여러 클래스에 걸쳐 공통 동작을 재사용해야 할 때, 다중 상속이 필요할 때, 스택 가능 변형을 통해 기능을 조합하고 확장해야 할 때 주로 사용하고, 추상 클래스는 클래스 계층 구조에서 공통된 속성과 동작을 정의할 때, 생성자 파리미터를 사용해야 할 때, 단일 상속 계층 구조에서 공통 기능을 제공할 때 사용합니다.

객체 지향 프로그래밍의 지향점이 코드의 구조를 명확하게 하고, 코드의 재사용성을 높이며 유지보수를 용이하게 하는 데 있기 때문에 상황에 맞게 프로그래밍 언어에서 제공해주는 기능 들을 적절히 선택해서 활용하는 것이 중요합니다.

이번 글에서 스칼라의 Trait와 Mix-in에 대해서 알아보았는데요. 스칼라 언어에 특화된 객체 지향의 내용을 다룰 수 있었습니다.
다음 글에서는 스칼라의 객체 지향 프로그래밍에서 큰 역할을 담당하고 있는 Case Class에 대해 살펴보겠습니다.

감사합니다.

comments 0