Kotlin by 키워드: 상속보다 위임을 선택해야 하는 이유
Kotlin은 간결하고 효율적인 코드를 작성하도록 돕는 다양한 언어적 기능을 제공한다.
그중에서도 by 키워드는 위임(delegation)을 손쉽게 구현할 수 있게 해주는 도구로, 객체지향 프로그래밍과 합성(composition)의 이점을 극대화할 수 있도록 설계되었다.
이번 포스팅에서는 Kotlin의 by 키워드 사용법과 왜 상속보다 위임을 사용하는 것이 더 나은 선택인지를 중심으로 살펴본다.
1. 상속보다 위임을 선호해야 하는 이유
1.1 상속의 한계와 문제점
상속은 객체지향 프로그래밍에서 널리 사용되는 도구이다. 이를 통해 부모 클래스의 기능을 자식 클래스가 물려받아 재사용성을 극대화할 수 있다. 하지만 상속은 몇 가지 단점을 내포하고 있다.
- 강한 결합(Strong Coupling):
자식 클래스는 부모 클래스의 구현 세부 사항에 강하게 결합된다. 이는 부모 클래스의 변경이 자식 클래스에 영향을 미치는 문제를 유발할 수 있다. - 유연성 부족:
Java와 Kotlin에서 클래스는 단일 상속만을 지원하므로, 다중 기능을 상속받아야 하는 경우 구조적으로 제약이 생길 수 있다. - 클래스 계층 구조의 복잡성:
상속을 무분별하게 사용하면 클래스 계층 구조가 불필요하게 복잡해져 유지보수가 어려워질 수 있다.
1.2 위임의 장점
위임은 상속과 달리 클래스 간의 느슨한 결합(loose coupling)을 유지하며 코드 재사용성을 높이는 데 도움을 준다. 상속 대신 위임을 사용하면 다음과 같은 이점이 있다.
- 유연한 설계:
여러 객체의 기능을 위임받아 사용할 수 있으므로 다중 상속의 제약을 우회할 수 있다. - 캡슐화 강화:
내부적으로 다른 객체의 기능을 활용하되, 외부에서는 해당 객체의 세부 사항을 감출 수 있다. - 독립적인 변경 가능:
위임받은 객체의 변경이 위임하는 객체에 직접적인 영향을 주지 않으므로 유지보수가 용이하다.
2. Kotlin에서의 by 키워드 사용법
Kotlin은 위임 패턴을 간결하게 구현할 수 있도록 by 키워드를 제공한다. 이 키워드는 클래스나 인터페이스를 다른 객체에 위임할 때 사용된다. 이를 통해 중복 코드를 최소화하고 간단한 문법으로 위임을 구현할 수 있다.
2.1 인터페이스 위임
다음은 by 키워드를 사용하여 인터페이스 구현을 위임하는 간단한 예시이다.
interface Greeter {
fun greet()
}
class SimpleGreeter : Greeter {
override fun greet() {
println("Hello from SimpleGreeter!")
}
}
class DelegatingGreeter(private val greeter: Greeter) : Greeter by greeter
위 코드에서 DelegatingGreeter 클래스는 Greeter 인터페이스의 구현을 SimpleGreeter 객체에 위임한다.
이를 활용하면 다음과 같이 사용할 수 있다.
fun main() {
val greeter = SimpleGreeter()
val delegatingGreeter = DelegatingGreeter(greeter)
delegatingGreeter.greet() // "Hello from SimpleGreeter!" 출력
}
public interface Greeter {
void greet();
}
public class SimpleGreeter implements Greeter {
@Override
public void greet() {
System.out.println("Hello from SimpleGreeter!");
}
}
public class DelegatingGreeter implements Greeter {
private final Greeter greeter;
public DelegatingGreeter(Greeter greeter) {
this.greeter = greeter;
}
@Override
public void greet() {
greeter.greet();
}
}
public class Main {
public static void main(String[] args) {
Greeter simpleGreeter = new SimpleGreeter();
Greeter delegatingGreeter = new DelegatingGreeter(simpleGreeter);
// Test the delegation
delegatingGreeter.greet();
}
}
2.2 프로퍼티 위임
Kotlin은 프로퍼티의 Getter와 Setter를 다른 객체나 함수에 위임할 수 있도록 지원한다. 대표적으로 Lazy, Observable과 같은 기본 제공 위임자를 사용할 수 있다.
class Example {
val lazyValue: String by lazy {
println("Computed!")
"Hello, Lazy!"
}
}
fun main() {
val example = Example()
println(example.lazyValue) // "Computed!" 출력, "Hello, Lazy!" 출력
println(example.lazyValue) // 캐싱된 값인 "Hello, Lazy!"만 출력
}
3. by를 활용한 위임의 실제 사례
3.1 로깅(logging) 위임
위임을 통해 특정 클래스가 로깅 기능을 별도의 로깅 클래스에 위임할 수 있다.
interface Logger {
fun log(message: String)
}
class ConsoleLogger : Logger {
override fun log(message: String) {
println("Log: $message")
}
}
class Service(private val logger: Logger) : Logger by logger {
fun execute() {
log("Service is executing.")
}
}
fun main() {
val logger = ConsoleLogger()
val service = Service(logger)
service.execute() // "Log: Service is executing." 출력
}
4. 결론
Kotlin의 by 키워드는 위임 패턴을 간결하게 구현할 수 있도록 설계된 강력한 도구이다. 이를 통해 상속의 단점을 극복하고, 보다 유연하고 확장 가능한 코드를 작성할 수 있다.
"상속보다는 위임을 선호하라"는 객체지향 설계의 원칙은 Kotlin의 철학과도 잘 맞아떨어진다. 위임은 객체 간의 결합도를 낮추고 코드의 재사용성을 높이는 동시에, 유지보수와 확장성을 개선할 수 있는 강력한 방법이다. Kotlin의 by 키워드를 활용하여 이러한 설계 원칙을 코드에 녹여보길 바란다.
Kotlin에서는 상속보다 위임을 사용하라는 의미에서 상속을 모두 여는 것이 아닌 open 키워드를 사용해서 상속을 사용할 class만 구분하도록 하였다.
긴 글 읽어 주셔서 감사합니다.
'JAVA & KOTLIN' 카테고리의 다른 글
[KOTLIN] Kotlin에서 Value Object 언제 사용할까? (2) | 2024.12.21 |
---|---|
[JAVA] java 1.8에서 변경 된 time (0) | 2024.12.17 |
[KOTLIN] Kotlin의 check와 require (2) | 2024.12.14 |
Kotlin - List to Array, Array to List (0) | 2021.11.06 |
Spring zip 파일 다운로드 (0) | 2021.06.15 |