객체지향개론을 들었다면 객체지향적인 설계를 도와주는 SOLID 원칙을 나눠보고자 합니다. SOLID 원칙은 객체지향 설계를 위한 5가지 원칙이며, 오늘은 첫번째 원칙인 SRP (Single Responsibility Principle; 단일책임원칙)에 대해서 나눠보려고 합니다. 이런 원칙이 왜 필요한지 알아보는 시간이 되길 바랍니다.
- There should never be more than one reason for a class to change.
클래스가 하나의 책임만을 가져야 한다고 하는데, 그렇다면 책임이란 무엇인가?
→ 이전 글 "객체의 역할과 책임"에서 역할에서 기인한 어떠한 행위를 책임이라고 정의했다.
이 주장을 검토하기 위해 두 가지 예시를 살펴보자.
첫 번째로, 로또 번호를 담는 LotteryNumber
클래스를 보자.
data class LotteryNumber(val number: Int) {
init {
require(number in 1 .. 45) { "에러메세지" }
}
}
이 클래스는 단순히 숫자의 유효성을 검증하는 책임을 가진다. 하나의 함수만을 수행하며, SRP를 준수하는 것처럼 보인다.
두 번째로, 중복되지 않은 6개의 번호를 담는 Lottery
클래스를 살펴보자.
class Lottery (val lotteryNumbers: List<LotteryNumber>) {
init {
require(lotteryNumbers.size == 6) { "에러메세지" }
require(lotteryNumbers.toSet().size == 6) { "에러메세지" }
}
}
이 클래스는 6개의 번호가 중복되지 않음을 검증하는 역할을 한다. 검증 로직이 여러 줄이지만, 결국 하나의 역할을 수행하는 것이므로 단일 책임 원칙을 어긴다고 보기 어렵다.
즉, 하나의 책임을 수행하기 위해 여러 개의 함수나 로직이 필요할 수 있으며, 단순히 "하나의 함수 수행만을 책임으로 본다"는 접근은 적절하지 않다.
class UserService {
// 모두 사용자 관리와 관련된 기능으로, 동일한 액터(관리자)가 사용
fun createUser(user: User): User { ... }
fun findUserById(id: Long): User { ... }
fun updateUserProfile(id: Long, profile: Profile): User { ... }
}
// 모두 UI 렌더링과 관련된 인터페이스
interface Clickable {
fun onClick()
}
interface Draggable {
fun onDrag()
}
// UI 담당 액터가 모든 기능을 사용함
class Button : Clickable, Draggable {
override fun onClick() { println("Button clicked") }
override fun onDrag() { println("Button dragged") }
}
class PaymentProcessor {
fun processPayment(payment: Payment): Receipt {
// 결제 처리 로직
return Receipt()
}
}
// 여러 클라이언트가 사용하지만 모두 동일한 목적(결제 처리)으로 사용
class WebCheckout {
private val paymentProcessor = PaymentProcessor()
fun checkout(cart: Cart) {
val payment = createPayment(cart)
paymentProcessor.processPayment(payment)
}
}
class MobileApp {
private val paymentProcessor = PaymentProcessor()
fun purchase(product: Product) {
val payment = createPayment(product)
paymentProcessor.processPayment(payment)
}
}
액터란, (시스템이 동일한 방식으로 변경되기를 원하는) 사용자 집단을 의미한다. 액터는 한 명일수도, 여러 명일 수도 있다. 해당 클래스에 어떤 액터가 의존하고 있는지 생각할 때, 우리는 진짜 SRP에 조금 더 가까워질 수 있다.하나의 모듈은, 오직 하나의 액터에 대해서만 책임져야 한다. - Robert C. Martin