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