일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- Redis
- Pay
- 바운디드컨텍스트
- 신입
- zuul
- 개발자
- springboot
- springcloud
- docker
- armeria
- webframework
- Spring
- kakao
- spring6
- IDDD
- Kotlin
- java17
- 반버논
- 값객체
- spring-web
- MongoDB
- Conference
- ddd
- ifkakao
- spring caching
- springboot3
- 애그리거트
- mongo
- spring scheduler
- MSA
- Today
- Total
Easy Understanding
웹 백엔드 관점으로 본 디자인 패턴 정리(2) - 전략 패턴(Strategy Pattern) 본문
앞으로 패턴들에 대해서 어떻게 백엔드의 관점에서 사용할 것이며,
얼마나 유용할지 평가를 해보려고 한다.
애초에 패턴들을 실용적인 관점에서 검토하지 않으면 의미가 없다는 생각이다.
이 공부가 나의 실무 코드에 도움이 되어야하니 그런 점들을 위해서 정리해두려고 한다.
그러나 딱 내 학습 수준에 맞는 평가가 나올 것 같아서 그 점은 참고해야 한다.
추가로 디자인 패턴의 개념에 대한 기초 설명은 패스하려고 한다.
전략 패턴
- 필요 개념: 컴포지션
- 활용도: 부담없이 사용해볼만 함
- 난이도: 간단
- 패턴이 필요한 상황: 상속 상황에서 내부 코드의 빈번한 중복
보통 이 패턴에 가장 많이 나오는 예제는 Duck에 대한 예제이다.
quack, fly 메서드가 나오고 여러 오리종류가 나오는 그 예제다.
헤드퍼스트에서 예로 들어서 유명하지만,
솔직히 이런 예시는 기초를 이해할 때나 도움이 되지 실제 프로그램과는 너무 동떨어진다.
백엔드 어플리케이션을 개발하면서 상속이 많아지는 순간이 종종 존재하곤 한다.
스프링을 기준으로 보통 두 레이어에서 상속이 많이 발생한다.
1. 서비스: @Service 어노테이션을 달고 있는 스프링 빈
2. 도메인 객체: 다양하기는 하지만 JPA 기준 @Entity가 달린 객체가 대표적이다.
서비스에서는 공통의 상위 클래스가 있고 다양한 요구사항에 따라서 하위 서비스가 생성되는 식이다.
결제를 예로 들면 이런 식으로 구성이 될 수가 있을 것 같다.
public interface PaymentService { ... }
public class CardPaymentService implements PaymentService { ... }
public class MobilePaymentService implements PaymentService { ... }
public class KakaoPaymentService implements PaymentService { ... }
과연 이게 끝일까?
비즈니스 요구사항은 변화무쌍해서 여기서 끝나지 않을 가능성이 무조건 백퍼센트다.
ios, google이 추가될 수도 있고, 다른 결제수단이 추가될 수도 있고,
같은 결제수단인데 살짝 다른 서비스가 필요할 수도 있다.
일단 클래스가 늘어나는 걸 막을 수 없는 건 확정이다.
일단 처음에 클래스가 몇 종류 되지 않을 때는 복붙으로 개발하는 게 맞다.
그러다가 슬슬 중복이 보인다 싶은 때가 오는데 그때가 전략패턴이 슬슬 도입될 때이다.
@Service
public class CardPaymentServiceA implements PaymentService{
public void startPayment(){
... 수십줄의 로직 A ...
}
public void endPayment(){
... 수십줄의 로직 B ...
}
public void cancelPayment(){
... 수십줄의 로직 C ...
}
}
@Service
public class CardPaymentServiceB implements PaymentService{
public void startPayment(){
... 수십줄의 로직 A ...
}
public void endPayment(){
... 수십줄의 로직 B ...
}
public void cancelPayment(){
... 수십줄의 로직 D ...
}
}
정말 싫은 상황이지만 어쩌다보니 거의 다 비슷한데 약간 비슷한 로직의 카드결제가 하나가 더 추가되었는데,
(이런 일은 정말 일어날 수 있다) 딱 cancelPayment만 코드가 다르다.
그럼 당연히 CardPaymentService A와 B의 중복을 빼내야 할 것이고 그 때 전략패턴을 사용하면 된다.
@Service
public class CardPaymentServiceA implements PaymentService{
private StartPaymentBehavior spb;
private EndPaymentBehavior epb;
private CancelPaymentBehavior cpb;
public CardPaymentServiceA(){
this.spb = new startMethodA();
this.epb = new endMethodB();
this.cpb = new cancelMethodC();
}
public void startPayment(){
spb.start();
}
public void endPayment(){
epb.end();
}
public void cancelPayment(){
cpb.cancel();
}
}
아마도 CardPaymentServiceB에서는
this.cpb = new cancelMethodD();
가 사용될 것으로 예상할 수 있다.
또한 전략 패턴을 통해서 유닛 테스트를 하기도 좀 더 편해진 것 같다.
원래대로였으면 각 서비스별로 테스트 코드를 다 만들어야 했지만,
이렇게 중복 코드를 모아두면 각 전략 클래스만 테스트할 수 있어서 편리하다.
추가로 상속 때문에 복잡해진 코드를 컴포지션을 이용해서 간단하게 만들었다는 점을 기억하면 좋다.
이 패턴에 대해서 정리하자면
'상속이 많아져서 중복이 겉잡을 수 없어져 복붙이 많이 필요한 상황이라면 도입을 고려해볼만 하다.'
애초에 협업하는 사람들이 따라가기 어려운 부분도 적어서 부담없이 도입해볼만 한 것 같다.
다만 한두개의 상속 케이스로 이 패턴을 도입하는 건 좀 아닌 것 같다.
'Study' 카테고리의 다른 글
웹 백엔드 관점으로 본 디자인 패턴 정리(4) - 데코레이터 패턴(Decorator Pattern) (0) | 2022.05.06 |
---|---|
웹 백엔드 관점으로 본 디자인 패턴 정리(3) - 옵저버 패턴(Observer Pattern) (0) | 2022.05.06 |
웹 백엔드 관점으로 본 디자인 패턴 정리(1) - 디자인 패턴의 분류와 문법 (0) | 2022.05.05 |
DDD를 적용한 간단한 결제 컨텍스트 개발해보기(with CQRS) (0) | 2022.04.03 |
(5) DDD와 아키텍처 - Layered, Hexagonal, CQRS, Event-Sourcing (0) | 2022.03.06 |