trait 개념

Scala에서 **trait**는 인터페이스와 유사한 개념으로, 여러 클래스에 공통적으로 적용될 수 있는 메서드필드를 정의하는 추상 타입입니다. trait다중 상속을 지원하며, 하나 이상의 trait를 상속받을 수 있습니다. 이는 객체 지향 프로그래밍과 함수형 프로그래밍 모두에서 매우 유용하게 사용됩니다.

주요 특징:

  1. 인터페이스처럼 동작: trait는 추상 메서드를 정의할 수 있으며, 이를 구현하는 클래스에서 구체적인 메서드로 오버라이드해야 합니다. 이는 Java나 Python의 인터페이스와 유사합니다.
  2. 구현 제공 가능: trait는 추상 메서드뿐만 아니라, 구체적인 구현을 가진 메서드도 정의할 수 있습니다. 이는 Java의 인터페이스와는 달리, 일부 메서드를 미리 구현할 수 있다는 점에서 더 유연합니다.
  3. 다중 상속 가능: 클래스는 여러 trait를 상속받아 다양한 기능을 조합할 수 있습니다. 이는 다중 상속을 직접적으로 지원하지 않는 언어들(Python, Java 등)에서 인터페이스를 사용하는 방식과 다릅니다.
  4. 클래스 상속과 함께 사용 가능: Scala 클래스는 하나의 클래스를 상속하면서도 여러 개의 trait를 믹스인할 수 있습니다.

예시:

trait Animal {
  def sound(): String  // 추상 메서드
}

trait Pet {
  def owner: String = "Unknown owner"  // 기본 구현 제공
}

class Dog(val name: String) extends Animal with Pet {
  def sound(): String = "Bark"  // 추상 메서드 구현
}

val dog = new Dog("Buddy")
println(dog.sound())  // "Bark"
println(dog.owner)    // "Unknown owner"

설명:

  1. trait Animal: sound()라는 추상 메서드를 가지고 있어, 이를 상속받는 클래스에서 반드시 구현해야 합니다.
  2. trait Pet: owner 필드에 기본 구현을 제공하고 있으며, 이를 상속받는 클래스가 재정의하지 않아도 사용할 수 있습니다.
  3. class Dog: AnimalPet 두 가지 trait를 상속받고 있으며, sound() 메서드를 구현함으로써 Animal의 추상 메서드를 완성합니다.

결론적으로, trait공통적인 동작을 여러 클래스에서 재사용하거나 다중 상속을 구현하는 데 매우 유용한 도구입니다. 이는 Scala의 객체 지향과 함수형 프로그래밍 패러다임에서 중요한 역할을 합니다.

다형성 구현 방식 선택 기준

**구체적인 상태와 생성자 로직을 공유해야 한다면 abstract class**를 사용하고, **단순히 메서드나 인터페이스 같은 역할을 한다면 trait**를 사용하는 것이 좋습니다. Scala에서는 trait가 더 가볍고 유연하므로, 인터페이스처럼 쓰이는 경우가 많습니다.

언제 abstract class를 사용해야 하나요?