Kotlin

Kotlin - 컴패니언 객체

J_Bin 2022. 6. 15. 16:51

Companion Object (컴패니언 객체) : 프로그램을 실행할 때 고정적으로 가지는 메모리로 객체 생성 없이 사용할 수 있다.(정적 변수?)

 

# Companion Object & Singleton pattern의 사용

package chap02.section1



class Person {
    var id : Int = 0
    var name : String = "Youngdeok"
    companion object {
        var language : String = "Korean"
        fun work() {
            println("working...")
        }
    }
}



fun main() {

    println(Person.language)            // 인스턴스를 생성하지 않고 기본값 사용
    Person.language = "English"         // 기본값 변경 가능
    println(Person.language)            // 변경된 내용 출력
    Person.work()
    //println(Person.name)            // name은 컴패니언 객체가 아니므로 오류
}


/*
    Person 클래스의 language는 객체의 생성 없이도 접근할 수 있게 되었다. 물론 work() 멤버 메서드도 객체 생성 없이 실행할 수 있다.
    컴패니언 객체는 실제 객체의 싱글톤(Singleton)으로 정의된다.
    Singleton : d전역 변수를 사용하지 않고 객체를 하나만 생성하도록 하여, 생성된 객체를 어디에서든지 참조할 수 있도록 하는 디자인 패턴
    사용 이유 ? 객체가 서로 동일한 정보를 가질 때 하나의 메모리만 유지해 자원의 낭비를 줄일 수 있기 때문이다.
 */

 

# Object 선언

package chap02.section1

// (1) Object 키워드를 사용한 방식
object OCustomer {
    var name : String = "Kildong"
    fun greeting() = println("Hello World OCustomer")
    val HOBBY = Hobby("Basketball")
    init {
        println("Init!")
    }
}

// (2) 컴패니언 객체를 사용한 방식
class CCustomer {
    companion object {
        const val HELLO = "hello"       // 상수 표현
        var name = "Joosol"
        @JvmField val HOBBY = Hobby("Football")
        @JvmStatic fun greeting() = println("Hello world CCustomer")
    }
}

class Hobby(val name : String)



fun main() {
    OCustomer.greeting()                // 객체의 접근 시점
    OCustomer.name = "Dooly"
    println("name = ${OCustomer.name}")
    println(OCustomer.HOBBY.name)

    CCustomer.greeting()
    println("name = ${CCustomer.name}, HELLO = ${CCustomer.HELLO}")
    println(CCustomer.HOBBY.name)
}

/*
    object로 선언된 OCustomer는 멤버 프로퍼티와 메서드를 객체 생성 없이 이름의 점(.) 표기법으로 바로 사용할 수 있다.
    이것 역시 단일 인스턴스를 생성해 처리하기 때문에 싱글톤 패턴에 이용된다.
    object 선언 방식을 사용하면 접근 시점에서 객체가 생성된다.
    그렇기 때문에 생성자 호출을 하지 않으므로 object 선언에는 주 생성자와 부 생성자를 사용할 수 없다.
    하지만 초기화 블록인 init이 들어갈 수 있는데 최초 접근에서 실행된다.
    object 선언에서도 클래스나 인터페이스를 상속할 수 있다.
* */

 

# Object 표현식 : object 표현식은 object 선언과 달리 이름이 없으며 싱글톤이 아니다. 따라서 object 표현식이 사용될 때마다 새로운 인스턴스가 생성된다. 결과적으로 이름이 없는 익명 내부 클래스로 불리는 형태를 object 표현식으로 만들 수 있다.

 

package chap02.section1

/* object 표현식 */

open class Superman() {
    fun work() = println("Taking photos")
    fun talk() = println("Talking with people.")
    open fun fly() = println("Flying in the air")
}


fun main() {
    val pretendedMan = object : Superman(){         // (1) object 표현식으로 fly() 함수 재정의
        override fun fly() {
            println("I'm a not a real SuperMan. I can't fly")
        }
    }
    pretendedMan.work()
    pretendedMan.talk()
    pretendedMan.fly()

}

/*
   (1)번에 익명 객체가 object 표현식으로 만들어졌다. 여기서 익명 객체는 Superman 클래스를 상속해 fly() 메서드를 오버라이딩하고 있다.
   결국 하위 클래스를 만들지 않고도 Superman 클래스의 fly() 메서드를 오버라이딩해 변경했다.
* */