기존의 도서를 검색을 할 때 최적화된 검색 전략에 따라 전달 받은 TitleQuery를 통해 각각 정해진 SQL 쿼리문을 switch 문을 통해 분기하여 선택하는 방식이였다. 하지만 이 방식은 TitleQuery가 추가되거나 수정이 되면 이 메소드의 로직 또한 변경이 필요 한 점, switch 문이 포함하는 로직을 재사용 할 수 없다는 문제등이 있다. 실제로 추천 로직에서도 같은 형태의 switch문이 중복되서 사용되고 있다. 따라서 이러한 문제를 인식하고 리팩토링을 실시 한다.
[기존의 코드]
private Page<Book> selectBooksEntity(@NonNull TitleQuery titleQuery, Pageable pageable) {
TitleType type = titleQuery.getTitleType();
switch (type) {
case KOR_SG, KOR_MT_OVER_TWO -> {
return bookRepository.findBooksByKorNatural(titleQuery.getKorToken(), pageable);
}
case KOR_MT_TWO -> {
return bookRepository.findBooksByKorMtFlexible(titleQuery.getKorToken(), pageable);
}
case ENG_SG -> {
return bookRepository.findBooksByEngBool(titleQuery.getEngToken(), pageable);
}
case ENG_MT -> {
return bookRepository.findBooksByEngMtFlexible(titleQuery.getEngToken(), pageable);
}
case ENG_KOR_SG -> {
return bookRepository.findBooksByEngKorBool(titleQuery.getEngToken(),
titleQuery.getKorToken(), pageable);
}
case ENG_KOR_MT -> {
return bookRepository.findBooksByEngKorNatural(
titleQuery.getEngToken(),
titleQuery.getKorToken(),
pageable);
}
default -> throw new IllegalArgumentException("Invalid title type: " + type);
}
}
@RequiredArgsConstructor
@Component
public class EngNaturalSt implements SelectStrategy {
private final BookRepository bookRepository;
@Override
public Page<Book> select(TitleQuery titleQuery, Pageable pageable) {
return bookRepository.findBooksByEngNatural(titleQuery.getEngToken(), pageable);
}
}
@Service
public class BookFinderImpl implements BookFinder<Page<BookDto>, Pageable>{
private final Map<TitleType,SelectStrategy> strategyMap;
public BookFinderImpl(BookRepository bookRepository) {
this.strategyMap = new EnumMap<>(TitleType.class);
strategyMap.put(KOR_SG, new KorNaturalSt(bookRepository));
strategyMap.put(KOR_MT_OVER_TWO, new KorNaturalSt(bookRepository));
strategyMap.put(KOR_MT_TWO, new KorBoolSt(bookRepository));
strategyMap.put(ENG_SG,new EngBoolSt(bookRepository));
strategyMap.put(ENG_MT,new EngBoolSt(bookRepository));
strategyMap.put(ENG_KOR_SG, new EngKorBoolSt(bookRepository));
strategyMap.put(ENG_KOR_MT, new EngKorNaturalSt(bookRepository));
}
@Override
public Page<BookDto> findBooks(TitleQuery titleQuery, Pageable target) {
TitleType type = titleQuery.getTitleType();
SelectStrategy strategy = strategyMap.get(type);
if(strategy == null){
throw new IllegalArgumentException("Invalid title type: " + type);
}
return strategy.select(titleQuery,target).map(BookDto::new);
}
}
그러고 나서 Switch문으로 분기되던 EnumBookFinder 대신 전략을 map 형태로 가지고 있으며, 생성자에서 map에 저장 한 뒤, 매개 변수로 들어오는 titleQuery안에 담겨진 TityeType의 형태에 따라서 Data JPA 메소드를 선택하게 했다.