학습
Kotlin 기본적인 디자인 패턴
Kotlin 기본적인 디자인 패턴 — 중급
기본적인 디자인 패턴
1. 도입 (왜 배워야 하는가)
디자인 패턴은 소프트웨어 개발에서 반복적으로 발생하는 문제를 해결하기 위한 일반적인 해결책을 제공합니다. 실무에서 우리는 다양한 요구 사항과 복잡한 비즈니스 로직을 처리해야 합니다. 이때 디자인 패턴을 이해하고 활용하는 것은 코드의 유지보수성과 확장성을 높이는 데 큰 도움이 됩니다.
만약 디자인 패턴을 모른다면, 코드가 복잡해지고 중복이 발생할 수 있으며, 이는 결국 버그를 초래하고 팀원 간의 협업을 어렵게 만들 수 있습니다. 또한, 코드를 이해하고 수정하는 데 많은 시간을 소모하게 되어 생산성이 떨어질 수 있습니다.
2. 핵심 개념 설명
디자인 패턴은 주로 세 가지 카테고리로 나뉩니다: 생성 패턴, 구조 패턴, 행동 패턴.
| 카테고리 | 설명 | 예시 |
|---|---|---|
| 생성 패턴 | 객체 생성 방식에 대한 패턴 | 싱글톤 패턴, 팩토리 패턴 |
| 구조 패턴 | 객체와 클래스의 조합 방식에 대한 패턴 | 어댑터 패턴, 프록시 패턴 |
| 행동 패턴 | 객체 간의 상호작용 방식에 대한 패턴 | 옵저버 패턴, 전략 패턴 |
실생활 비유: 디자인 패턴은 마치 요리의 레시피와 같습니다. 특정 요리를 만들기 위한 단계와 재료들이 정해져 있어, 처음 요리를 하는 사람도 쉽게 따라 할 수 있도록 도와줍니다.
3. 기본 코드 예제
싱글톤 패턴
싱글톤 패턴은 애플리케이션 내에서 하나의 인스턴스만 생성하도록 보장하는 패턴입니다.
object Singleton {
var value: Int = 0
fun increment() {
value++
}
}
fun main() {
Singleton.increment()
println(Singleton.value) // 1
Singleton.increment()
println(Singleton.value) // 2
}
실행 결과:
1
2
object Singleton: 싱글톤 객체를 선언합니다.var value: Int = 0: 정수형 변수를 초기화합니다.fun increment(): value를 1 증가시키는 메서드를 정의합니다.main()함수에서Singleton.increment()를 호출하여 value를 증가시키고, 그 값을 출력합니다.
4. 실전 활용 예제
1. 쇼핑몰에서 장바구니를 구현할 때 (전략 패턴)
장바구니에 다양한 할인 전략을 적용할 수 있습니다.
interface DiscountStrategy {
fun applyDiscount(price: Double): Double
}
class NoDiscount : DiscountStrategy {
override fun applyDiscount(price: Double) = price
}
class PercentageDiscount(private val percentage: Double) : DiscountStrategy {
override fun applyDiscount(price: Double) = price * (1 - percentage / 100)
}
class ShoppingCart(private val discountStrategy: DiscountStrategy) {
fun calculateTotal(price: Double): Double {
return discountStrategy.applyDiscount(price)
}
}
fun main() {
val cartWithNoDiscount = ShoppingCart(NoDiscount())
println(cartWithNoDiscount.calculateTotal(100.0)) // 100.0
val cartWithDiscount = ShoppingCart(PercentageDiscount(10.0))
println(cartWithDiscount.calculateTotal(100.0)) // 90.0
}
실행 결과:
100.0
90.0
2. 로그 시스템 구현에서 (옵저버 패턴)
로그 시스템에서 다양한 로그 레벨에 따라 동작하는 시스템을 구현할 수 있습니다.
interface Observer {
fun update(message: String)
}
class ConsoleLogger : Observer {
override fun update(message: String) {
println("Console Logger: $message")
}
}
class Logger {
private val observers = mutableListOf<Observer>()
fun addObserver(observer: Observer) {
observers.add(observer)
}
fun log(message: String) {
observers.forEach { it.update(message) }
}
}
fun main() {
val logger = Logger()
logger.addObserver(ConsoleLogger())
logger.log("This is a log message.") // Console Logger: This is a log message.
}
실행 결과:
Console Logger: This is a log message.
5. 흔한 실수와 주의사항
- 싱글톤 객체의 잘못된 사용:
- 옵저버 패턴에서 주의할 점:
- 디자인 패턴은 소프트웨어 설계의 문제를 해결하는 유용한 도구입니다.
- 생성, 구조, 행동 패턴으로 나뉘며 각 패턴은 특정 상황에서 효과적입니다.
- 실무에서 디자인 패턴을 활용하면 코드의 유지보수성과 확장성을 높일 수 있습니다.
- 고급 디자인 패턴 (예: 커맨드 패턴, 상태 패턴)
- SOLID 원칙 (소프트웨어 설계 원칙)
- 테스트 주도 개발 (TDD)
- 잘못된 코드:
class Singleton {
companion object {
val instance = Singleton()
}
}
- 올바른 코드:
object Singleton
- 옵저버를 등록한 후 로그를 남기지 않으면 로그가 출력되지 않음. 항상 옵저버를 등록 후 로그를 남기도록 주의해야 함.
6. 정리
다음에 학습하면 좋은 주제: