case class vs object

핵심 차이

case class object
인스턴스 수 여러 개 가능 딱 하나 (singleton)
데이터 보유 ✓ (필드 있음) △ (상태 없는 게 보통)
new 없이 생성 ✓ (apply 자동) 해당 없음 (이미 singleton)
패턴 매칭 ✓ (unapply 자동) ✓ (값 자체로 매칭)
equals / hashCode 자동 생성 기본 참조 동일성
copy

case class — 데이터를 담는 타입

case class Point(x: Int, y: Int)

val p1 = Point(1, 2)
val p2 = Point(1, 2)
p1 == p2   // true (값 비교)
p1.copy(x = 10)  // Point(10, 2)

object — singleton / 유틸 / 상수

object Direction:
  val North = "N"
  val South = "S"
  def opposite(d: String): String = ...

Direction.North  // "N"

같이 쓰는 패턴: companion object

case class User(name: String, age: Int)

object User:           // companion object
  def guest: User = User("Guest", 0)  // 팩토리 메서드 등

sealed trait + case class/object 조합

ADT(Algebraic Data Type) 표현할 때 자주 쓴다.

sealed trait Shape
case class Circle(r: Double)        extends Shape  // 데이터 있음
case class Rect(w: Double, h: Double) extends Shape
case object Empty                   extends Shape  // 데이터 없음, singleton

case object는 필드 없는 케이스에 쓴다. case class와 달리 인스턴스가 하나뿐이므로 () 없이 쓴다.