목표
웹 소켓 핸들러에서 Realtime AI 의 응답의 이벤트 타입에 따라 분기문을 통해 처리 방법을 구분하는 것이 클린 코드가 아니라는 생각이 들었다. 객체 지향의 10대 원칙 중 하나가 else if, else 문을 활용하지 않는 것이다. 각 이벤트 타입에 맞게 처리(handle) 로직을 클린하게 구현하는 방법에 대해 학습한다.
과정
분기문을 통해서 구분짓지 않는다면 이제 다른 방법으로는 switch 문 혹은 인터페이스 와 Map 을 활용한 방법이 있을 것이다
switch 문을 활용하는 방법은 if 문보다 성능과 가독성 측면에서 더 뛰어난 구현 방식이라고 볼 수 있으나 각각의 케이스마다 처리 로직이 커진다면 이 switch 문을 품고 있는 메서드 또한 무거워지므로 클린코드라고 볼 수는 없을 것이다.
인터페이스와 각 케이스에 맞게 구현체를 구성하고 Map 자료구조를 통해서 해당 타입에 맞는 구현체를 가져와 처리한다면 클린코드라 볼 수 있을 것이다.
인터페이스
public interface RealtimeEventHandler {
RealtimeEventType getSupportedType();
void handle(String sessionId, AiToServerRealtimeMessage message);
}
인터페이스는 두 개의 메서드로 이루어진다.
getSupportedType() 는 해당 핸들러가 어떤 타입에 대한 핸들러인지를 반환하는 메서드이다.
handle(sessionId, message) 는 이벤트 타입에 맞는 처리를 위한 메서드이다.
구현체
위의 인터페이스를 구현한 예시 구현체이다.
@Component
@RequiredArgsConstructor
public class AudioDeltaEventHandler implements RealtimeEventHandler {
private final AudioStreamingUseCase audioStreamingUseCase;
@Override
public RealtimeEventType getSupportedType(){
return RealtimeEventType.RESPONSE_AUDIO_DELTA;
}
@Override
public void handle(String sessionId, AiToServerRealtimeMessage message){
audioStreamingUseCase.forward(sessionId, new ServerToClientAudioMessage(message.delta()));
}
}
디스패처
@Slf4j
@Component
public class RealtimeEventDispatcher {
private final Map<RealtimeEventType, RealtimeEventHandler> handlerMap;
@Autowired
public RealtimeEventDispatcher(List<RealtimeEventHandler> handlers) {
this.handlerMap = handlers.stream()
.collect(Collectors.toUnmodifiableMap(
RealtimeEventHandler::getSupportedType,
handler -> handler
));
}
public void dispatch(String sessionId, AiToServerRealtimeMessage message){
RealtimeEventType type = message.type();
log.info("Realtime Event type: {}", type);
if(!handlerMap.containsKey(type)) return;
RealtimeEventHandler handler = handlerMap.get(type);
handler.handle(sessionId, message);
}
}
디스패처는 내부 필드에 Map 저장 공간을 가져 핸들러를 보관한다. 여기서 주목할 부분이 생성자의 파라미터이다. 파라미터의 타입을 List<RealtimeEventHandler> 로 정의한다면 스프링 빈 객체로 등록된 RealtimeEventHandler 구현체들이 자동 주입이 된다. 따라서, 해당 객체를 생성하는 시점에 Map 에 핸들러를 등록할 수 있다.
'개발일지' 카테고리의 다른 글
| 웹 소켓 핸들러 예외 처리 (0) | 2025.06.20 |
|---|---|
| 주변 사용자 조회 로직 변경 (0) | 2025.03.11 |
| 사용자 위치 변경에 대한 기능 수정 (0) | 2025.03.11 |
| [소프티어 부트캠프] 지도(공유) 기능에 대한 고찰 (1) | 2025.03.11 |