[코틀린 기초] 코틀린 싱글턴, 동반객체 (object, companion)
싱글톤이란
싱글톤 패턴에서 싱글톤, 즉 단하나의 인스턴스를 토대로 개발해나가는 디자인 패턴의 하나이다. 멀티스레드 환경에서도 안전하게 유일한 인스턴스를 가져야합니다.
싱글톤을 구현하는 방법은 굉장히 많습니다. 이러한 디자인 패턴은 한가지 언어에 국한되지 않고 다양하게 적용할 수 있기 때문에 싱글톤 패턴이라는 디자인 패턴을 보고싶은 분들의 경우에는 아래의 블로그 포스팅을 참조해주세요.
https://sas-study.tistory.com/478
코틀린에서의 싱글톤
코틀린은 자바처럼 직접 클래스로 구현하는 형태가 아닌 문법적으로 지원해준다. object라는 객체 선언 키워드를 통해 싱글톤을 지원합니다.
object Singleton {
}
싱글톤 클래스의 함수나 변수를 사용할 때는 자바의 정적 static에 접근하듯이 클래스 한정자를 사용합니다.
object Singleton {
val a = 1234
fun printA() = println(a)
}
fun main() {
println(Singleton.a)
Singleton.printA()
// 1234
// 1234
}
이러한 객체 선언을 통해 좀더 응용해보자면, static 키워드를 이용하여 XXUtil 클래스를 만들고 사용해본적이 있을 것이다.
예제) LocalDateTimeUtil
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
object LocalDatetimeUtils {
val now: LocalDateTime
get() = LocalDateTime.now()
const val DEFAULT_FORMAT = "yyyy-MM-dd"
fun same(a: LocalDateTime, b: LocalDateTime) :Boolean {
return a == b
}
fun getNowString(): String {
return now.format(DateTimeFormatter.ofPattern(DEFAULT_FORMAT))
}
}
fun main() {
println(LocalDatetimeUtils.now)
println(LocalDatetimeUtils.now)
println(LocalDatetimeUtils.now)
println(LocalDatetimeUtils.DEFAULT_FORMAT) // yyyy-MM-dd
val now = LocalDateTime.now()
println(LocalDatetimeUtils.same(now, now)) // true
val nowString = LocalDatetimeUtils.getNowString()
println(nowString)
}
코틀린을 문법을 학습하지 않고 자바에서 싱글톤을 구현하듯이 코틀린에서 클래스를 설계하게 되면 static inner 클래스에서 막히게 된다.
필자도 어?? 왜 inner 클래스 선언이 안돼지?? 하고 당황했던 기억이 있다.
코틀린에서는 별도의 inner 클래스 키워드인 companion object 가 있다.
class MyClass {
companion object {
}
}
- 한 클래스 내에서 한개의 companion object를 선언할 수 있다.
- companion object는 익명 클래스처럼 동작하지만 스스로 이름을 가지게 할 수 있다.
- 이름을 가지게 된다면 접근하는 방법이 달라진다.
class MyClass {
private constructor()
companion object CompanionObjectName {
val a = 1234
fun newInstance() = MyClass()
}
}
fun main() {
println(MyClass.a)
println(MyClass.newInstance())
// 이렇게도 가능하나 생략 가능
println(MyClass.Companion.a)
println(MyClass.Companion.newInstance())
// 이름이 바뀌게 된다면 -> CompanionObjectName
println(MyClass.CompanionObjectName.a)
println(MyClass.CompanionObjectName.newInstance())
}
- 여기서 MyClass는 일종의 간단한 싱글턴으로 볼 수 있다.
- companion 동반객체는 클래스당 하나만 존재하므로 사실 부모 클래스로부터의 공간이 이미 확보된 상태이기 때문에 접근하는 방법에 자바의 static 접근 방법과 동일하게 접근할수 있다. 하지만 별도로 이름을 통해 명시해서 접근도 가능하다.
- 이름이 없다면 Companion이라는 키워드로, 이름이 있다면 별도로 이름을 통해 접근할 수 있다.