비슷한 듯 다른 두 개념 시리즈(?)의 두 번째 파트는 책임과 역할입니다. 객체지향 프로그래밍에서 자주 등장하는 두 개념은, 혼용해서 사용하기 쉽습니다.(일단 저부터) 이를 바로 잡아보려 진짜 의미를 찾아보겠습니다.
책임 Responsibility
책임이란 객체에 의해 정의되는 응집도 있는 행위의 집합으로, 객체가 유지해야 하는 정보와 수행할 수 있는 행동에 대해 개략적으로 서술한 문장이다. 즉, 객체의 책임은 객체가 '무엇을 알고 있는가'와 '무엇을 할 수 있는가'로 구성된다.
여기서 객체가 무엇을 알고 있는가는 데이터로, 무엇을 할 수 있는가는 함수로 치환할 수 있습니다.
결제 서비스를 예시로 들어보겠습니다. 결제를 위해선 사용자 정보와 금액 정보(데이터), 실제로 결제를 수행할 행동(함수)이 필요합니다. 이를 우리는 결제 서비스의 '책임'이라고 이야기합니다.
struct Payment {
var user: User // 데이터(무엇을 알고 있는가?)
var price: Int // 데이터(무엇을 알고 있는가?)
// 함수(무엇을 할 수 있는가?)
func pay(user: User, price: Int) {
print("\(user.name)이 \(price)원 계산했습니다.")
}
}
SRP(단일 책임 원칙)가 말하는 '책임'의 의미는 이러한 데이터와 함수가 변경되어야 할 이유가 오직 '하나'라는 것을 뜻합니다. 만약 주문 서비스의 책임을 결제 서비스가 가지고 있다면 이를 위반하게 되겠죠?
역할 Role
객체가 수행하는 책임의 집합을 뜻한다.
위에서 살펴본 사용자, 가격 데이터와 결제 함수를 묶어 우리는 '결제 서비스'라고 부릅니다. 여기서 결제 서비스가 역할이 됩니다.(책임의 집합)
역할은 여러 객체가 수행할 수 있는 특징이 있습니다. 결제 서비스가 요구하는 책임을 수행할 수 있다면, 그것은 결제 서비스의 역할에 해당하게 되기 때문입니다.
/// 결제 시스템 '역할'을 추상화
protocol PaymentSystem {
var user: User { get set }
var price: Int { get set }
func pay(user: User, price: Int)
}
/// 책임을 다할 수 있다면 결제 시스템 역할을 수행할 수 있다는 뜻!
struct KakaoPayment {
var user: User
var price: Int
func pay(user: User, price: Int) {
print("카카오페이에서 \(user.name)이 \(price)원 계산했습니다.")
}
}
/// 책임을 다할 수 있다면 결제 시스템 역할을 수행할 수 있다는 뜻!
struct TossPayment {
var user: User
var price: Int
func pay(user: User, price: Int) {
print("토스에서 \(user.name)이 \(price)원 계산했습니다.")
}
}
위 코드에서 결제 시스템의 '역할'을 카카오페이와 토스 모두 수행이 가능합니다.
정리하기
- 이 객체가 무엇을 해야 하는가?(역할) > 결제 시스템
- 객체는 어떤 기능과 데이터를 관리해야 하는가?(책임) > 사용자, 가격 데이터, 결제 기능
결국 역할이 구체화되면 객체가 가져야 할 책임이 정해지고, 명확한 책임 분리는 좋은 객체 지향 설계의 핵심이 될 수 있습니다.
'CS' 카테고리의 다른 글
추상화와 일반화, 비슷한듯 다른 두 개념 (1) | 2025.02.02 |
---|---|
테스트 더블? 두 번 테스트 하는 건가요? (0) | 2025.01.21 |
스레드와 메모리,, 비슷한 거 아니었나요? (0) | 2025.01.15 |