object
04 May 2019object는 언제 사용하는가
- 싱글턴을 정의할 때
- companion object를 정의할 때
- 익명 내부 클래스를 정의할 때
싱글턴 구현하기
구현 방법
코틀린에서는 아래와 같은 방법으로 싱글턴을 정의 하는것을 object 선언이라고 부른다
object Payroll {
val allEmployees = arrayListOf<Person>()
fun calculateSalary() {
for (person in allEmployees) {
...
}
}
}
Payroll.allEmployees.add(Person(...))
Payroll.calculateSalary()
- 클래스와 마찬가지로 프로퍼티, 메소드, 초기화 블록 등이 들어갈 수 있다
- 생성자를 쓸수 없다
- 일반 클래스의 인스턴스와 달리 object 선언문이 있는 위치에서 즉시 싱글턴 객체가 만들어지므로 생성자가 필요없다
중첩 object를 사용한 구현 방법
클래스 안에서 object 선언을 할 수 있다
data class Person(val name: String) {
object NameComparator: Comparator<Person> {
override fun compare(p1: Person, p2: Person): Int{
p1.name.compareTo(p2.name)
}
}
}
val persons = listOf(Person("Bob"), Person("Alice"))
println(persons.sortedWith(Person.NameComparator))
// 결과
[Person("Alice"), Person("Bob")]
- 바깥 클래스의 인스턴스마다 중첩 object 선언에 해당하는 인스턴스가 하나씩 따로 생기는 것이 아니다
companion object
코틀린은 자바 static 키워드를 지원하지 않는다. 대신 아래의 방법을 활용한다
- 패키지 수준의 최상위 함수
- 자바의 정적 메소드 역할을 거의 대신할 수 있다
- object 선언
- 코틀린 최상위 함수가 대신할 수 없는 역할이나 정적 필드를 대신할 수 있다
- 클래스 내부 정보에 접근해야 하는 함수가 필요할 때 클래스의 중첩된 object 선언의 멤버 함수로 정의해야 한다
- 예) 팩토리 메소드
중첩 object와 companion object 차이
중첩 object
class Outer {
object NestedClass {
val no: Int = 0
fun myFun() {}
}
}
fun main(args: Array<String>) {
Outer.NestedClass.no
Outer.NestedClass.myFun()
}
companion object
- Outer 클래스 내부에서 자신의 클래스 멤버처럼 이용할 수 있다
- object 클래스명을 사용하지 않고 companion object가 정의된 클래스 이름을 사용할 수 있다
- 결국 자바의 정적 메소드 호출이나 정적 필드 사용 구문과 같아진다
class Outer {
companion object NestedClass {
val no: Int = 0
fun myFun() {}
}
// Outer 클래스 내부에서 자신의 클래스 멤버처럼 이용할 수 있다
fun outerFun() {
no
myFun()
}
}
fun main(args: Array<String>) {
Outer.NestedClass.no
Outer.NestedClass.myFun()
// object 클래스명을 사용하지 않고 이용할 수 있다
Outer.no
Outer.myFun()
}
companion object 구현하기
- 부 생성자가 2개 있는 클래스를 companion object 안에서 팩토리 클래스를 정의하는 방식으로 변경해 본다
부 생성자가 두개 있는 클래스
class User {
val nickname: String
constructor(email: String) {
nickname = email.substringBefore('@')
}
constructor(facebookAccountId: Int) {
nickname = getFacebookName(facebookAccountId)
}
}
부생성자를 팩토리 메소드로 변경하기
class User private constructor(val nickname: String) {
companion object {
fun newSubscribingUser(email: String) =
User(email.substringBefore('@'))
fun newFacebookUser(accountId: Int) =
User(getFacebookName(accountId))
}
}
val subscribingUser = User.newSubscribingUser("bob@gamil.com")
val facebookUser = User.newFacebookUser(4)