이전 회사에서, 상품권 교환소라는 도메인을 Spring Core 4.x 버전에서 SpringBoot 3.x 버전으로 마이그레이션 할 일이 있었다. 이 때 몇 가지 문제상황과, 바꾸고 싶었던 점이 있었는데, 잊기 전에 글로 남겨보려고 한다.
@RequiredArgsConstructor
@Service
public class LegacyService {
private final PartnerOne partnerOne;
private final PartnerTwo partnerTwo;
// ...
// 조회 (예시)
public String retrieve(Map<String, Object> objectMap){ //
// ...
String identifier = (String) objectMap.get("identifier");
switch (identifier){
case "partnerOne" : return partnerTwo.retrieve();
case "partnerTwo" : return partnerOne.retrieve();
default: throw new RuntimeException("custom exception");
}
// ...
}
// 승인 ...
// 취소 ...
기존 소스(레거시)에서 개선하고 싶었던 불편함들은 아래와 같다.
각 제휴사는 이 인터페이스를 구현하여 고유의 동작들(retrieve
, approve
, cancel
)을 정의하고, getIdentifier()
메서드를 통해 각 제휴사를 식별할 수 있도록 변경
또한, 팩토리 패턴을 도입하여 switch-case
문을 대신하여 제휴사를 식별하고 적절한 서비스 클래스를 반환하는 구조로 변경.
이러한 구조 변경을 통해 유연성과 확장성을 개선
public interface PartnerService {
String retrieve();
String approve();
String cancel();
Identifier getIdentifier();
}
// getIdentifier() 매서드를 통해 파트너사를 구분하도록 각각에 맞는 enum타입 리턴
@Component
@RequiredArgsConstructor
public class PartnerServiceFactory {
private final Map<Identifier, PartnerService> partnerServiceBeans = new HashMap<>();
public PartnerServiceFactory(List<PartnerService> partnerServiceList) { // List 형태의 파트너서비스 beans 주입
partnerServiceList.forEach(each -> partnerServiceBeans.put(each.getIdentifier(), each));
}
public PartnerService getPartnerService(Identifier identifier) {
return partnerServiceBeans.get(identifier);
}
}
@Service
@RequiredArgsConstructor
public class RetrieveService {
private final PartnerServiceFactory partnerServiceFactory;
public String retrieve(RequestDto requestDto){
PartnerService partnerService = partnerServiceFactory.getPartnerService(requestDto.identifier());
return partnerService.retrieve();
}
}
개선함으로써 얻어낸 효과