포스트

(구조패턴) Strategy Pattern - 발송 후처리 전략 설립하기 (메시징 서비스를 예제로)

(구조패턴) Strategy Pattern - 발송 후처리 전략 설립하기 (메시징 서비스를 예제로)

이전 글에서 팩토리 패턴을 활용해 다양한 메시지 발송 채널(SMS, EMAIL, KAKAO 등)을
유연하게 처리할 수 있는 구조를 소개했습니다.

이번 글에서는 그 다음 단계로, 발송 이후의 후처리 로직까지 통합하는 설계를 소개합니다.
바로 CompositeSenderService입니다.


실무에서 필요한 후처리 로직

메시지 발송 이후에는 보통 다음과 같은 후처리가 필요합니다:

  • 발송 결과 DB 저장
  • 실패 시 재시도 예약
  • 장애 알림 전송 (Slack, Email)
  • 모니터링 시스템 연동

이런 로직은 채널과 무관하게 공통적으로 반복되며,
전략 패턴(Strategy Pattern)을 통해 유연하게 처리할 수 있습니다.


구조 구성도

이전 글까지에서, 발송 팩토리 구조에 대해서 설명했습니다. (SenderFactory)

classDiagram
    class CompositeSenderService {
        <<interface>>
        +send(request)
    }

    class CompositeSenderServiceImpl {
        +send(request)
    }

    class SenderChannelFactory {
        +getHandler(channelType): SenderChannelHandler
    }

    class SenderChannelHandler {
        <<interface>>
        +send(request): SendResponse
    }

    class SmsSenderChannelHandler
    class EmailSenderChannelHandler
    class KakaoSenderChannelHandler

    class SyncStrategyService {
        <<interface>>
        +process(request, response)
    }

    class SaveToDbStrategyHandler
    class RetryStrategyHandler
    class AlertStrategyHandler

    CompositeSenderService <|.. CompositeSenderServiceImpl
    CompositeSenderServiceImpl --> SenderChannelFactory
    CompositeSenderServiceImpl --> SyncStrategyService

    SenderChannelFactory --> SenderChannelHandler
    SenderChannelHandler <|.. SmsSenderChannelHandler
    SenderChannelHandler <|.. EmailSenderChannelHandler
    SenderChannelHandler <|.. KakaoSenderChannelHandler

    SyncStrategyService <|.. SaveToDbStrategyHandler
    SyncStrategyService <|.. RetryStrategyHandler
    SyncStrategyService <|.. AlertStrategyHandler

핵심 인터페이스

SenderChannelHandler.java

1
2
3
4
public interface SenderChannelHandler {
    NotifyChannelType getType();
    ResponseEntity<SendResponse> send(SendRequest request);
}

이전 글에서 설명했기 때문에 생략하겠습니다.

SyncStrategyService.java

1
2
3
public interface SyncStrategyService {
    void process(SendRequest request, SendResponse response);
}

CompositeSenderService 구현

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Service
@RequiredArgsConstructor
public class CompositeSenderServiceImpl implements CompositeSenderService {

    private final SenderChannelFactory senderChannelFactory;
    private final List<SyncStrategyService> strategies;

    @Override
    public ResponseEntity<SendResponse> send(SendRequest request) {
        // 1. 채널별 Sender 선택
        SenderChannelHandler handler = senderChannelFactory.getChannel(request.getNotifyChannelType());

        // 2. 메시지 발송
        ResponseEntity<SendResponse> response = handler.send(request);

        // 3. 후처리 전략 실행 (중요한 부분)
        strategies.forEach(strategy -> strategy.process(request, response.getBody()));

        return response;
    }
}

여기에서 후처리 전략 실행 부분을 통해서, 모든 전략을 시도할 수 있습니다. (DB 저장, 재시도, 장애알림 등등)

후처리 전략 실행 부분

1
strategies.forEach(strategy -> strategy.process(request, response.getBody()));

전략 구현 예시

SaveToDbStrategyHandler.java

1
2
3
4
5
6
7
8
9
10
@Component
public class SaveToDbStrategyHandler implements SyncStrategyService {
    @Override
    public void process(SendRequest request, SendResponse response) {
        // DB 저장 로직
        if (response != null) {
            // repository.save(...)
        }
    }
}

RetryStrategyHandler.java

1
2
3
4
5
6
7
8
9
@Component
public class RetryStrategyHandler implements SyncStrategyService {
    @Override
    public void process(SendRequest request, SendResponse response) {
        if (response != null && !response.success()) {
            // 재시도 예약 로직
        }
    }
}

호출 예시

1
compositeSenderService.send(request);

외부에선 CompositeSenderService 하나만 호출하면,
내부에서 채널 선택 → 발송 → 후처리가 일관된 흐름으로 실행됩니다.


장점 요약

  • Factory + Strategy 결합으로 책임 분리 및 확장성 확보
  • 단일 진입점을 통한 호출 단순화
  • 전략 추가/삭제가 쉬워 유지보수에 강함
  • 테스트 용이 (각 전략 단위 테스트 가능)

마무리

CompositeSenderService팩토리 패턴으로 확장 가능한 채널 발송 구조전략 패턴으로 유연한 후처리를 통합한 설계입니다.

서비스가 점점 커지고 다양한 요구사항이 붙을수록, 이러한 구조적 설계는 개발자에게 큰 무기가 된다고 생각합니다.

다음 글에서는 템플릿 메서드 패턴을 활용한 후처리 로직의 중복 제거 방법을 예시를 들면서 소개하겠습니다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.