2025-10-30

1일 1아티클

LY

준비되지 않은 생성자

사례


  /**
  * A video player for a file specified by [videoUri]. 
  * 
  * Call [play] to play the video, but [prepare] must be called before calling `play`.
  * Otherwise `play` will throw [IllegalStateException].
  */
  class FooVideoPlayer(
      private val videoUri: Uri,
      ... // other options
  ) {
      private var preparedValue: PreparedValue? = null

      fun prepare() {
          if (preparedValue != null) {
              error("Already prepared")
          }

          val preparedValue = ... // execute `prepare` logic
      }

      fun play() {
          val currentValue = preparedValue
          if (currentValue == null) {
              error("Not prepared yet")
          }

          // ... play `videoUri`.
      }
  }

문제 상황

  • FooVideoPlayer.play() 호출 시 동영상 재생 가능
  • 이때, prepare() 을 먼저 호출하여 preparedValue 설정 필수
  • prepare() 을 건너뛰고 play() 호출 시 error 발생
  • 즉, FooVideoPlayer준비되지 않은 상태의 안전한 처리가 안되고 있는 상황!

해결 방안

  1. 초기화 시 prepare() 실행
    • 생성자나 initalizer에서 prepare() 로직 실행
    • 장점 : 많은 속성을 읽기 전용으로 생성 가능
    • 단점 : 안전하지 않은 코드가 될 수 있음
    • 보완 : 생성자를 private 설정하고 별도의 팩토리 함수 정의 후, 해당 함수에 prepare() 로직 작성
  2. play() 호출 시 처음에 prepare() 실행
    • 인스턴스 생성 시점이 아닌, 처음 play() 호출 시점에 로직 실행
    • 장점 : 인스턴스 생성되어도 play() 미호출 가능성이 높고 prepare() 비용이 높을 때 유리
    • 단점 : prepare() 에서 확정하는 속성을 가변(var)으로 두어야 함
    • 보완 : Kotlin의 경우, lazy 처럼 최초 접근 시 로직 실행 매커니즘을 제작해 사용
  3. prepare() 전에 play() 호출 못하도록 강제
    • 정적 타입 사용 언어의 경우, prepare() 후에만 play() 정의하도록 구현
    • 애초에 잘못 사용했을 때 컴파일 자체가 불가능하도록 하는 방법
    • prepare() 비용이 높아서 호출자가 이 함수의 실행 시점을 제어하고 싶을 때 유리
    • 해결 방안 1의 팩토리 함수를 클래스화한 것
    • 장점 : prepare() 된 인스턴스를 FooVideoPlayer의 캐시로 보유
    • 장점2 : 단계적 초기화 상태 관리 가능

준비되지 않은 인스턴스는 사용하지 못하도록 할 것

오늘 배운 것

  1. AI 관통 프로젝트
    • RAG 기반 AI 비서 기능 개발

내일 할 일

참고자료

results matching ""

    No results matching ""