[번역]-Delegates를 Kotlin에게 위임하기(1편)

hongbeom
hongbeom
Apr 7 · 7 min read

코틀린에서 위임을 사용하는 방법을 알아봅니다.

Photo by 鏡飛 匙 on Unsplash

이 글은 Murat Yener님의 글을 한국어로 번역한 글입니다. 원문 링크👇

위임이란 객체가 헬퍼 객체로 어떠한 요청을 위임하여 처리하는 설계 패턴입니다. 헬퍼 객체는 원래 객체를 대신하여 요청을 처리하고 원래 객체가 결과를 사용할 수 있도록 할 책임을 가지고 있습니다.

Class Delegates

마지막으로 제거한 항목을 복구할 수 있는 ArrayList 의 사용 사례가 있다고 가정해 보겠습니다. 기본적으로 마지막으로 제거한 항목을 참조할 수 있는 기능을 가진 ArrayList만 있으면 됩니다.

한 가지 방법은 ArrayList 클래스를 상속받는 것입니다. 이 새로운 클래스는 ArrayList를 상속받기 때문에 MutableList 인터페이스의 구현보단 ArrayList 구현과 매우 밀접하게 연관되어 있습니다.

삭제된 아이템의 참조를 유지하기 위해 remove() 함수를 오버라이드 하고 MutableList의 비어있는 구현을 다른 객체에게 위임하는 것은 좋지 않을 것입니다. Kotlin은 대부분의 작업을 내부 ArrayList 인스턴스에 위임하고 해당 작업의 동작을 커스텀하는 방법을 제공합니다. Kotlin의 새로운 키워드인 by를 통해서 말입니다.

클래스 위임의 작동 방식을 살펴보겠습니다. by 키워드를 사용하면 Kotlin이 자동으로 코드를 생성하여 innerList 인스턴스를 위임자로 사용합니다.

by 키워드는 Kotlin에게 MutableList 인터페이스에서 innerList 라는 이름의 내부 ArrayList 인스턴스로 기능을 위임하도록 지시합니다. ListWithTrash는 여전히 내부 ArrayList 객체에 직접 연결되는 메소드를 제공하여 MutableList 인터페이스의 모든 함수를 지원합니다. 게다가 이제 우리의 사용에 맞게 커스텀할 수도 있습니다.

내부 동작

이제 어떻게 작동하는지 살펴봅시다. ListWithTrash 바이트 코드에서 분해된 Java 코드를 보면 Kotlin 컴파일러가 실제로 내부 ArrayList 객체에서 해당 함수를 호출하는 래퍼 함 수를 만드는 것을 볼 수 있습니다.

참고 : Kotlin 컴파일러는 Decorator Pattern이라는 또 다른 디자인 패턴을 사용하여 생성된 코드에서 클래스 위임을 지원합니다. Decorator 패턴에서 Decorator 클래스는 Decorate할 클래스와 동일한 인터페이스를 공유합니다. Decorator 클래스는 대상 클래스의 내부 참조를 유지하고 인터페이스와 함께 제공된 모든 퍼블릭 메소드를 래핑하거나 Decorate합니다.

Delegates는 특정 클래스에서 상속할 수 없는 경우에 특히 유용합니다. 클래스 위임을 사용하면 클래스가 클래스 계층의 일부가 아니게 됩니다. 대신 동일한 인터페이스를 공유하고 원래 타입의 내부 객체를 decorate합니다. 즉, 퍼블릭 API 사용 중단 없이 구현을 쉽게 전환할 수 있습니다.

Delegating properties

클래스 위임 외에도 by 키워드를 사용하여 프로퍼티를 위임할 수도 있습니다. 대리자는 프로퍼티 위임을 통해 프로퍼티의 get set 함수에 대한 호출을 처리할 책임을 가집니다. 이 함수는 getter/setter 로직을 다른 객체 간에 재사용해야 하는 경우 매우 유용할 수 있으며 단순히 백업 필드 이상으로 쉽게 기능을 확장할 수 있습니다. 다음과 같이 정의된 Person 클래스가 있다고 가정해 보겠습니다.

class Person(var name: String, var lastname: String)

이 클래스의 name 프로퍼티에는 몇 가지 형식에 대한 지정된 요구 사항이 있습니다. nameset 되면 첫 번째 문자는 대문자로, 나머지는 소문자로 형식을 지정하려고 합니다. 또한 name을 업데이트 할 때, 업데이트 숫자 프로퍼티를 자동으로 증가시키려고 합니다.

다음과 같이 이 기능을 구현해볼 수 있습니다.

이 작업은 잘 수행되지만 요구 사항이 변경되고 lastname이 변경될 때마다 updateCount를 증가시키려면 어떻게 해야 할까요? 로직을 복사/붙여넣기 하여 커스텀 setter를 작성할 수도 있지만, 갑자기 각 프로퍼티에 대해 동일한 setter를 작성해야 할 수도 있습니다.

두 가지 setter 모두 거의 동일해보입니다. 프로퍼티 위임을 사용하면 setter와 getter를 프로퍼티에 위임하여 코드를 재사용할 수 있습니다.

클래스 위임과 마찬가지로 by를 사용하여 프로퍼티를 위임할 수 있으며, 사용자가 프로퍼티 구문을 사용할 때 Kotlin이 대리인을 사용할 코드를 생성합니다.

이렇게 변경하면 name lastname 프로퍼티는 FormatDelegate 클래스에 위임하게 됩니다. 이제 FormatDelegate의 코드를 살펴보겠습니다. getter만 위임해야 하는 경우 대리인 클래스는 ReadProperty<Any?, String>을 구현해야 하며, getter와 setter를 모두 위임해야 하는 경우 ReadWriteProperty<Any?, String>을 구현해야 합니다. 우리의 경우, FormatDelegateReadWriteProperty<Any?, String>을 구현해야 합니다. 왜냐하면 setter가 호출될 때 해당 포맷을 수행하려고 하기 때문입니다.

setter 및 getter 함수에는 두 가지 추가 파라미터가 있을 수 있습니다. 첫 번째 매개 변수는 thisRef이며 프로퍼티를 포함하는 객체를 나타냅니다. thisRef는 다른 프로퍼티를 확인하거나 다른 클래스 함수 호출 목적으로 객체 자체에 접근하는 데에 사용할 수 있습니다. 두 번째 매개 변수는 위임된 프로퍼티의 메타데이터에 접근하는데 사용할 수 있는 KProperty<*> 입니다.

요구 사항을 만족시키기 위해 thisRef를 사용하여 updateCount 프로퍼티에 접근하고 프로퍼티를 증가시키도록 하겠습니다.

내부 구현

이 작업의 작동 방식을 이해하기 위해, 분해된 Java 코드를 살펴보겠습니다. Kotlin 컴파일러는 name lastname 프로퍼티에 대한 FormatDelegate 객체의 private 참조와 우리가 추가한 로직을 포함하는 getters/setters를 유지하는 코드를 생성합니다.

컴파일러는 위임된 프로퍼티를 저장하는 KProperty[] 도 생성합니다. 생성된 name 프로퍼티의 getter와 setter를 살펴보면 인스턴스는 인덱스 0에 저장된 반면 lastname 프로퍼티는 인덱스 1에 저장됩니다.

이 트릭을 사용하면 모든 호출자가 일반 프로퍼티 구문을 사용하여 위임된 프로퍼티에 접근할 수 있습니다.

person.lastname = “Smith” 
// 생성된 setter를 호출하며, count를 증가시킵니다.
println(“Update count is $person.count”)

Kotlin은 delegates를 지원할 뿐만 아니라 Kotlin Standard 라이브러리에 내장된 delegates도 제공합니다. 자세한 내용은 다른 아티클을 참조해보세요.

Delegates는 작업을 다른 객체에 위임하고 코드를 보다 효율적으로 재사용할 수 있도록 지원합니다. Kotlin 컴파일러는 사용자가 Delegates를 원활하게 사용할 수 있도록 코드를 생성합니다. Kotlin은 프로퍼티나 클래스를 위임하기 위해 by 키워드와 함께 간단한 구문을 사용합니다. 내부에서 Kotlin 컴파일러는 퍼블릭 API에 대한 어떠한 변경도 노출시키지 않고 위임을 지원하기 위해 필요한 모든 코드를 생성합니다. 간단히 말해서, Kotlin은 Delegate들에게 필요한 모든 보일러 플레이트 코드를 생성하고 유지 관리하며 결과적으로 Delegate들을 Kotlin에게 위임할 수 있습니다.

hongbeomi dev

hongbeomi 개발블로그

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store