밤빵's 개발일지
[TIL]20241028 by 와 Delegation 본문
코틀린을 공부하면서 by 키워드와 위임 패턴(Delegation)이라는 새로운 개념을 알게 되었다. 위임 패턴은 객체지향 프로그래밍에서 자주 사용되는 디자인 패턴으로, 객체가 특정 기능을 다른 객체에게 위임(Delegation)하는 방식이다. 코틀린에서는 이 패턴을 지원하기 위해 by 키워드를 제공하며, 이를 사용하면 인터페이스 구현을 간결하고 효율적으로 처리할 수 있다. 이번 개발일지에서는 코틀린의 by 키워드를 활용한 위임 방법과 이로 인해 얻을 수 있는 장점을 정리해 보았다.
▶위임 패턴
위임 패턴(Delegation Pattern)은 객체가 특정 작업을 수행하기 위해 그 작업을 다른 객체에게 위임하는 디자인 패턴이다. 이 패턴을 사용하면 코드의 재사용성과 유연성이 높아지고, 복잡한 상속 구조를 피할 수 있다. 예를 들어, 클래스가 여러 기능을 제공해야 할 때 모든 기능을 직접 구현하지 않고, 해당 기능을 다른 객체에게 위임할 수 있다. 이를 통해 코드가 간결해지고 유지보수성이 향상된다.
▶ by 키워드를 사용한 위임
코틀린에서는 by 키워드를 사용하여 인터페이스 구현을 다른 객체에 위임할 수 있다. by 키워드는 클래스가 특정 인터페이스를 구현할 때, 그 구현을 다른 객체에게 위임하도록 도와준다. 이를 통해 반복적인 코드를 줄이고, 클래스 설계가 더욱 직관적으로 이루어진다.
▷예시: 인터페이스 위임
Printer라는 인터페이스를 PrinterDelegate 객체에 위임하는 방식으로 구현한 예시.
interface Printer {
fun printMessage(message: String)
}
class ConsolePrinter : Printer {
override fun printMessage(message: String) {
println("Console Printer: $message")
}
}
class PrinterDelegate(printer: Printer) : Printer by printer
fun main() {
val consolePrinter = ConsolePrinter()
val printerDelegate = PrinterDelegate(consolePrinter)
printerDelegate.printMessage("Hello, Kotlin!")
}
→ Printer는 printMessage 메서드를 가진 인터페이스이다.
→ ConsolePrinter는 Printer 인터페이스를 구현한 클래스로, 여기서 printMessage 메서드는 콘솔에 메시지를 출력한다.
→ PrinterDelegate 클래스는 Printer by printer 구문을 사용해 Printer 인터페이스의 구현을 printer 객체에 위임한다.
→ main 함수에서 PrinterDelegate 객체를 생성하고, 메시지를 출력할 때 위임된 ConsolePrinter의 printMessage 메서드가 호출된다.
▶ by 키워드를 활용한 장점
코드의 간결성
→ by 키워드를 사용하면 클래스가 인터페이스의 메서드를 하나하나 구현할 필요가 없어진다. 위 예시에서도 PrinterDelegate 클래스는 Printer 인터페이스의 모든 메서드를 by 키워드로 위임받아 구현했기 때문에, printMessage 메서드를 따로 정의할 필요가 없다.
유연한 코드 확장
→ 위임 패턴을 사용하면, 기능을 추가하거나 변경할 때 클래스 구조를 크게 수정하지 않아도 된다. 예를 들어, 위임받는 객체(printer)를 교체하는 것만으로 새로운 기능을 추가할 수 있다.
다중 인터페이스 구현
→ by 키워드를 사용해 여러 인터페이스를 동시에 구현할 수 있다. 이를 통해 복잡한 상속 구조를 피하고, 코드의 재사용성을 극대화할 수 있다.
▶ by 키워드의 실전 예시: 로그 시스템
위임 패턴은 실전에서 다양한 용도로 사용될 수 있다. 예를 들어, 로그 시스템을 구현할 때 여러 출력 방식(Console, File 등)을 by 키워드를 활용해 손쉽게 전환할 수 있다.
▷예시: 로그 시스템 구현
interface Logger {
fun log(message: String)
}
class ConsoleLogger : Logger {
override fun log(message: String) {
println("Console Log: $message")
}
}
class FileLogger : Logger {
override fun log(message: String) {
// 파일에 로그를 기록하는 코드 (여기서는 단순 출력으로 대체)
println("File Log: $message")
}
}
class LogManager(logger: Logger) : Logger by logger
fun main() {
val consoleLogger = ConsoleLogger()
val fileLogger = FileLogger()
val consoleLogManager = LogManager(consoleLogger)
consoleLogManager.log("Logging to console.")
val fileLogManager = LogManager(fileLogger)
fileLogManager.log("Logging to file.")
}
→ Logger 인터페이스를 통해 로그 메시지를 기록할 수 있는 메서드 log를 정의.
→ ConsoleLogger와 FileLogger는 각각 콘솔과 파일에 로그를 기록하는 구현체이다.
→ LogManager는 Logger 인터페이스를 by 키워드를 사용해 위임받아 구현하고, 인자로 전달된 logger 객체에 따라 로그 기록 방식을 쉽게 변경할 수 있다.
▶ by 키워드와 상속의 차이점
by 키워드를 사용한 위임과 클래스를 상속받아 구현하는 방식에는 몇 가지 중요한 차이점이 있다.
항목 | 상속 (Inheritance) | by 키워드 위임 (Delegation) |
코드 재사용성 | 상속받은 부모 클래스의 모든 기능 사용 가능 | 특정 기능을 필요한 객체에 위임 가능 |
유지보수성 | 부모 클래스 변경 시, 자식 클래스에도 영향 | 위임 객체 교체만으로 기능 확장 가능 |
클래스 계층의 복잡성 | 복잡한 계층 구조를 형성할 수 있음 | 단일 클래스에서 여러 기능 위임 가능 |
유연성 | 특정 클래스에 종속적일 수 있음 | 동적으로 위임 객체를 교체 가능 |
코틀린의 by 키워드를 활용한 위임 패턴은 코드의 간결성과 유연성을 크게 향상시킬 수 있는 유용한 기능이다. 기존에 자바에서 사용했던 상속 개념과 달리, by 키워드는 불필요한 코드의 중복을 줄이고, 기능 확장을 더욱 쉽게 만들어준다.
'Kotlin' 카테고리의 다른 글
[TIL]20241030 try-with-resources & use (4) | 2024.10.30 |
---|---|
[TIL]20241029 Nested Functions (3) | 2024.10.29 |
[TIL]20241027 sealed class 와 Enum (0) | 2024.10.27 |
[TIL]20241026 apply, with, run (2) | 2024.10.26 |
[TIL]20241025 오버로딩 & 오버라이딩 (1) | 2024.10.25 |