Kotlin의 위임(Delegation)
Kotlin의 위임(Delegation) 기능은 구현 상속의 강력한 대안으로, 보일러플레이트 코드 없이 유연하고 재사용 가능한 코드를 작성할 수 있게 해줍니다. 이 가이드에서는 Kotlin의 위임 기능의 다양한 측면을 상세히 살펴보겠습니다.
위임 기본 (Delegation Basics)
Kotlin에서는 by
키워드를 사용하여 인터페이스의 구현을 다른 객체에 위임할 수 있습니다. 이를 통해 컴포지션을 쉽게 구현할 수 있습니다.
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b
fun main() {
val base = BaseImpl(10)
Derived(base).print() // 출력: 10
}
이 예제에서 Derived
클래스는 Base
인터페이스의 구현을 b
객체에 위임합니다. 컴파일러는 Base
의 모든 메서드를 b
로 포워딩하는 코드를 자동으로 생성합니다.
위임된 인터페이스 멤버 오버라이딩 (Overriding Members of Delegated Interface)
위임을 사용하더라도 인터페이스의 메서드를 오버라이드할 수 있습니다. 오버라이드된 메서드는 위임 객체의 구현 대신 사용됩니다.
interface Base {
fun printMessage()
fun printMessageLine()
}
class BaseImpl(val x: Int) : Base {
override fun printMessage() { print(x) }
override fun printMessageLine() { println(x) }
}
class Derived(b: Base) : Base by b {
override fun printMessage() { print("abc") }
}
fun main() {
val base = BaseImpl(10)
Derived(base).printMessage() // 출력: abc
Derived(base).printMessageLine() // 출력: 10
}
이 예제에서 Derived
클래스는 printMessage()
를 오버라이드하여 자체 구현을 제공하지만, printMessageLine()
은 여전히 위임 객체의 구현을 사용합니다.
위임 객체의 동작 (Behavior of Delegated Object)
중요한 점은 오버라이드된 멤버가 위임 객체의 다른 메서드에서 호출되지 않는다는 것입니다. 위임 객체는 자신의 구현만을 사용합니다.
interface Base {
val message: String
fun print()
}
class BaseImpl(x: Int) : Base {
override val message = "BaseImpl: x = $x"
override fun print() { println(message) }
}
class Derived(b: Base) : Base by b {
override val message = "Message of Derived"
}
fun main() {
val b = BaseImpl(10)
val derived = Derived(b)
derived.print() // 출력: BaseImpl: x = 10
println(derived.message) // 출력: Message of Derived
}
이 예제에서 Derived
의 message
프로퍼티는 오버라이드되지만, BaseImpl
의 print()
메서드에서는 이 오버라이드된 값이 아닌 자신의 message
값을 사용합니다.
위임의 장점과 사용 사례
- 코드 재사용: 상속 없이 기존 구현을 재사용할 수 있습니다.
- 유연성: 런타임에 동적으로 구현을 변경할 수 있습니다.
- 캡슐화: 내부 구현을 숨기면서 인터페이스를 노출할 수 있습니다.
- 다중 상속 문제 해결: Java의 다중 상속 제한을 우회할 수 있습니다.
실제 사용 사례
- 데코레이터 패턴: 객체의 책임을 동적으로 추가할 수 있습니다.
interface Coffee {
fun getCost(): Double
fun getDescription(): String
}
class SimpleCoffee : Coffee {
override fun getCost() = 1.0
override fun getDescription() = "Simple coffee"
}
class MilkDecorator(private val coffee: Coffee) : Coffee by coffee {
override fun getCost() = coffee.getCost() + 0.5
override fun getDescription() = "${coffee.getDescription()}, milk"
}
2. 전략 패턴: 알고리즘을 동적으로 교체할 수 있습니다.
interface SortStrategy {
fun sort(list: List<Int>): List<Int>
}
class Sorter(private val strategy: SortStrategy) : SortStrategy by strategy
// 사용
val bubbleSort: SortStrategy = BubbleSortStrategy()
val quickSort: SortStrategy = QuickSortStrategy()
val sorter = Sorter(bubbleSort)
// 나중에 전략을 변경할 수 있음
// sorter = Sorter(quickSort)
3. 프록시 패턴: 객체에 대한 접근을 제어할 수 있습니다.
interface Image {
fun display()
}
class RealImage(private val filename: String) : Image {
override fun display() = println("Displaying $filename")
}
class ProxyImage(private val filename: String) : Image {
private var realImage: RealImage? = null
override fun display() {
if (realImage == null) {
realImage = RealImage(filename)
}
realImage?.display()
}
}
Kotlin의 위임 기능은 객체 지향 설계의 유연성을 크게 향상시킵니다. 이를 통해 코드 재사용성을 높이고, 더 모듈화된 구조를 만들 수 있습니다. 특히 상속으로 인한 문제(예: 취약한 기반 클래스 문제)를 피하면서도 코드를 효과적으로 구성할 수 있습니다.
하지만 위임을 과도하게 사용하면 코드의 복잡성이 증가할 수 있으므로, 적절한 상황에서 신중하게 사용해야 합니다. 특히 큰 프로젝트에서는 위임 관계를 명확히 문서화하고 관리하는 것이 중요합니다.
위임은 특히 레거시 코드를 리팩토링하거나, 테스트하기 어려운 코드를 개선할 때 유용한 도구가 될 수 있습니다. 또한 프레임워크나 라이브러리 설계 시 확장성과 유연성을 제공하는 데 큰 도움이 됩니다.
이 블로그의 다른글 :
2024.08.17 - [개발&프로그래밍] - [Kotlin] 객체 표현식과 선언(object expressions and object declarations)
[Kotlin] 객체 표현식과 선언(object expressions and object declarations)
Kotlin의 객체 표현식과 선언Kotlin에서 객체 표현식(object expressions)과 객체 선언(object declarations)은 클래스를 상속하거나 인터페이스를 구현하는 익명 객체를 생성하는 강력한 기능입니다. 이 가이
observerlife.tistory.com
2024.08.13 - [개발&프로그래밍] - [kotlin] 인라인 값 클래스(Inline Value Classes)
[kotlin] 인라인 값 클래스(Inline Value Classes)
Kotlin의 인라인 값 클래스(Inline Value Classes)Kotlin의 인라인 값 클래스(Inline Value Classes)는 성능 최적화와 타입 안전성을 동시에 제공하는 강력한 기능입니다.이 문서에서 인라인 값 클래스의 다양한
observerlife.tistory.com
2024.08.13 - [개발&프로그래밍] - [Kotlin] 열거형 클래스(Enum class)
[Kotlin] 열거형 클래스(Enum class)
Kotlin의 열거형 클래스Kotlin의 열거형 클래스(enum class)는 고정된 상수 집합을 표현하는 강력한 도구입니다.이 문서에서는 Kotlin 열거형 클래스의 다양한 사용법을 살펴보겠습니다. 기본 사용
observerlife.tistory.com
2024.08.13 - [개발&프로그래밍] - [Kotlin] 중첩 클래스와 내부 클래스
[Kotlin] 중첩 클래스와 내부 클래스
Kotlin의 중첩 클래스와 내부 클래스Kotlin에서 클래스 내부에 다른 클래스를 정의하는 방법은 코드의 구조화와 캡슐화를 위한 강력한 도구입니다. 이 문서에서는 중첩 클래스와 내부 클래스의 개
observerlife.tistory.com
2024.08.13 - [개발&프로그래밍] - [kotlin] 제네릭: in, out, where
[kotlin] 제네릭: in, out, where
Kotlin의 제네릭: in, out, whereKotlin의 제네릭은 타입 안전성과 코드 재사용성을 높이는 강력한 기능입니다.이 가이드에서는 Kotlin 제네릭의 다양한 측면을 상세히 살펴보겠습니다. 제네릭 기
observerlife.tistory.com
2024.08.12 - [개발&프로그래밍] - [kotlin] Sealed classes & interfaces
[kotlin] Sealed classes & interfaces
Kotlin의 Sealed 클래스와 인터페이스Kotlin의 sealed 클래스와 인터페이스는 클래스 계층 구조의 제어된 상속을 제공하는 강력한 기능입니다.이 가이드에서는 sealed 클래스와 인터페이스의 다양한 측
observerlife.tistory.com
2024.08.12 - [개발&프로그래밍] - [kotlin] 데이터 클래스(Data classes)
[kotlin] 데이터 클래스(Data classes)
Kotlin의 데이터 클래스Kotlin의 데이터 클래스(Data Classes)는 주로 데이터를 보유하는 용도로 사용되는 특별한 클래스입니다.이 가이드에서는 Kotlin 데이터 클래스의 다양한 측면을 상세히 살펴보겠
observerlife.tistory.com
2024.08.12 - [개발&프로그래밍] - [kotlin] 확장 기능(Extensions)
[kotlin] 확장 기능(Extensions)
Kotlin의 확장 기능Kotlin의 확장(Extensions) 기능은 기존 클래스나 인터페이스에 새로운 기능을 추가할 수 있게 해주는 강력한 도구입니다.이 가이드에서는 Kotlin 확장의 다양한 측면을 상세히 살펴
observerlife.tistory.com
Kotlin, 위임, Delegation, 인터페이스, 코드재사용, 디자인패턴, 객체지향프로그래밍, 컴포지션, 데코레이터패턴, 전략패턴, 프록시패턴, 코틀린문법, 안드로이드개발, 서버개발, 리팩토링
'개발&프로그래밍' 카테고리의 다른 글
[Kotlin] 타입 별칭(Type Aliases) (0) | 2024.08.18 |
---|---|
[Kotlin] 위임된 프로퍼티(Delegated Properties) (0) | 2024.08.17 |
[Kotlin] 객체 표현식과 선언(object expressions and object declarations) (0) | 2024.08.17 |
[kotlin] 인라인 값 클래스(Inline Value Classes) (0) | 2024.08.15 |
[Kotlin] 열거형 클래스(Enum class) (0) | 2024.08.15 |
댓글