SOLID 란 프로그래머가 시간이 지나도 유지 보수와 확장이 쉬운 시스템을 만들고자 할 때 이 원칙들을 함께 적용할 수 있다. SOLID 원칙들은 소프트웨어 작업에서 프로그래머가 소스 코드가 읽기 쉽고 확장하기 쉽게 될 때 까지 소프트웨어 소스 코드를 리팩터링하여 코드 냄새를 제거하기 위해 적용할 수 있는 지침이다.
단일 책임의 원칙(SRP): Single Responsibillity Principle
단일 책임의 원칙의 키워드는 다음과 같다.
- 클래스는 단 한 개의 책임을 가져야 한다.
- 클래스의 변경하는 이유는 단 한개여야 한다.
- 누가 해당 메소드의 변경을 유발하는 사용자인가?
단일 책임의 원칙이라는 것은 이해하기 난해하다. 명확한 책임을 도출하기까지 시간이 걸리기 때문에 처음부터 단일 책임을 지켜서 설계하는 것은 힘들다. 또 요구사항이 변경 될 경우 책임 또한 변경되게 된다. 그렇기에 지속해서 한 개의 클래스가 하나의 책임을 갖게 하기는 어렵다.
객체 지향 특성 중, 단일 책임 원칙과 가장 관계가 깊은 특성은 모델링을 담당하는 '추상화' 이다.
요구사항
- 카드 결제 시스템이 존재
- 현재 국내 결제를 지원하는 카드는 신한, 우리 카드가 존재
- 국내 결제 카드사들은 지속해서 추가
- 미래에 해외 결제 기능이 추가
- 신한 카드는 해외 결제가 가능
- 우리 카드는 해외 결제가 불가능
- 지속해서 카드사가 추가
기존 국내 카드 결제 서비스
public interface CardPaymentService {
void pay(CardPaymentDto.PaymentRequest req);
}
public class ShinhanCardPaymentService implements CardPaymentService {
@Override
public void pay(CardPaymentDto.PaymentRequest req) {
// .. 신한 카드 국내 결제 로직..
shinhanCardApi.pay(paymentRequest);
}
}
public class WooriCardPaymentService implements CardPaymentService {
@Override
public void pay(CardPaymentDto.PaymentRequest req) {
// .. 우리 카드 국내 결제 로직..
wooriCardApi.pay(paymentRequest);
}
}
추가될 해외 카드 결제 서비스
public interface CardPaymentService {
void pay(CardPaymentDto.PaymentRequest req);
void payOverseas(CardPaymentDto.PaymentRequest req);
}
public class ShinhanCardPaymentService implements CardPaymentService {
@Override
public void payOverseas(CardPaymentDto.PaymentRequest req) {
// .. 신한 카드 해외 결제 로직..
shinhanCardApi.pay(paymentRequest);
}
}
public class WooriCardPaymentService implements CardPaymentService {
@Override
public void payOverseas(CardPaymentDto.PaymentRequest req) {
// 우리 카드 결제는 해외 결제 기능이 없음...
}
}
신한 카드는 해외 결제를 할 수 있지만 우리 카드는 해외 결제 기능을 제공하지 않고 있다. 각 구현 클래스들은 CardPaymentService 인터페이스를 구현하고 있으므로 payOverseas 기능이 추가되면 우리 카드 결제는 반드시 해당 메서드를 구현해야 한다.
해외 결제만 되고 국내 결제가 안되는 카드사가 추가될 경우 위와 반대로 payOverseas 는 구현하고 pay 는 구현하지 못하게 된다.
SRP 에서 책임이란 변화에 대한 것이다.
국내 결제에서 해외 결제라는 책임이 하나 더 생긴 것이다. 그렇게 두 개의 책임이 생겼기에 클래스의 책임을 나누는 작업이 필요해졌다.
만약, 우리 카드가 해외 결제를 제공하고 다른 카드사들도 해외 결제를 제공한다면 국내, 해외 결제를 할 수 있고, 하나의 책임을 가질 수 있다고 볼 수 있으며 단일 책임의 원칙을 지켰다고 볼 수도 있다.
하지만 미래에 어떻게 될 것인지를 예측할 수 없기 때문에 단일 책임의 원칙을 지키는 것은 매우 어려운 일이다.
해외 결제 서비스와 국내 결제 서비스에 대한 두 개의 인터페이스를 만들어서 국내 결제와 해외 결제에 대한 책임을 분리했고 하나의 클래스가 하나의 책임을 갖도록 변경했다. 새로운 카드사 추가 시에 유연하게 확장을 할 수 있도록 할 수 있다.
즉, 단일 책임 원칙(SRP) 와 가장 관계가 깊은 특성은 '추상화' 라고 할 수 있다.
참조