Kotlin Delegate - 1

홍승범·2023년 4월 30일
0

Kotlin

목록 보기
5/8

1. 대리자를 통해 합성 구현하기

  • 문제 : 다른 클래스의 인스턴스가 포함된 클래스를 만들고, 그 클래스에 연산을 위임하고 싶다
    - 해법

    연산을 위임할 메소드가 포함된 인터페이스를 만들고, 클래스에서 해당 인터페이스를 구현한 다음, by카워드를 사용해 바깥쪽에 래퍼 클래스를 만든다

    최신 객체지향 디자인은 기능 추가시 상속보다는 합성을 선호한다.(Swift의 Delegate패턴등). 코틀린에서 by키워드는 포함된 객체에 있는 모든 public 함수를 이 객페를 담고있는 컨테이너를 통해 노출할 수 있다.

    interface Dialable { 
        fun dial(number: String): String
    }
    
    class Phone: Dialable {
        override fun dial(number: String): String = "Dialing $number"
        fun dial2(number: String): String = "Dialing2 $number"
    }
    
    interface Snappable {
        fun takePicture(): String
    }
    
    class Camera: Snappable {
        override fun takePicture(): String = "Taking Picture...."
    }

    폰 클래스와 카메라 클래스는 각각의 인터페이스를 구현하고 있다. 이때 스마트폰 클래스를 상속이 아니라 by를 통한 각 인스턴스에 위임할 수 있도록 구현할 수 있다.

    class SmartPhone(
        private val phone: Dialable = Phone(),
        private val camera: Snappable = Camera() 
    ): Dialable by phone, Snappable by camera
    
    fun main() {
        val sp = SmartPhone()
        sp.dial("01001010101")
        sp.takePicture()
        sp.dial2() // 없음
    }

    포함된 객체 (phone, camera인스턴스)는 SmartPhone을 통해 노출된 것이 아니라, 오직 포함된 객체의 선언된 인터페이스에 맞는 함수만 노출된다. dial2는 camera인스턴스에 포함되지만 인터페이스에는 포함되지 않아 노출되지 않는다.

2. lazy 대리자

  • 문제 : 어떤 속성이 필요할 때까지 해당 속성의 초기화를 지연시키고 싶다
    - 해법

    코틀린 표준 라이브러리의 lazy대리자를 사용한다.

    코틀린은 어떤 속성의 획득자와 설정자가 대리자라고 불리는 다른 객체에서 구현되어 있다는 것을 암시하기 위해 속성에 by키워드를 사용한다.
    lazy대리자를 사용하기 위해서는 처음 접근이 일어날 때 값을 계산하기 위해 만들어진 () -> T 형식의 초기화 람다를 제공해야 한다.

    public fun <T> lazy(initializer: () -> T): kotlin.Lazy<T> //(1)
    
    public fun <T> lazy(lock: kotlin.Any?, initializer: () -> T): kotlin.Lazy<T> //(2)
    
    public fun <T> lazy(mode: kotlin.LazyThreadSafetyMode, initializer: () -> T): kotlin.Lazy<T>//(3)
    • (1) : 기본, 스스로 동기화를 하는 함수

    • (2) : lazy인스턴스가 다수의 스레드간에 초기화를 동기화하는 방법을 명시

    • (3) : 동기화 락을 위해 제공된 객체를 사용

      다음 코드는 처음접근시 값을 초기화하는 코드이다. 해당변수에 처음 접근하게 될 때까지 계산을 지연시키는 동작을 한다.

      val ultimateAnswer: Int by lazy { 
      	println("computing the answer")
      	42
      }

      mode 속성이 없는 대리자의 기본값은 LazyThreadSafetyMode.SYNCHRONIZED이며 다른 각 값은 아래와 같다

    1. LazyThreadSafetyMode.SYNCHRONIZED : 오직 하나의 스레드만 Lazy인스턴스를 초기화 할 수 있게 락을 사용
    2. LazyThreadSafetyMode.PUBLICATION : 초기화 함수가 여러번 호출될 수 있지만, 첫 번째 리턴값만 사용된다
    3. LazyThreadSafetyMode.NONE : 락이 사용되지 않음.
profile
그냥 사람

0개의 댓글