프로젝트를 진행하면서 기능을 추가하다보니 동적인 쿼리가 필요해졌고 QueryDSL을 추가하게 되었다.
하지만 JPA와 QueryDSL를 함께 사용하다보니 한가지 의문이들었다.
바로 DI, OCP원칙을 생각했을때 QueryDSL코드를 JpaRepository의 구현체로 만드는게 과연 적절할지에 대한 의문 말이다..
그래서 일단 구현해보기로 했다..ㅎ!
Adapter 패턴은 서로 다른 인터페이스를 가진 두 개의 클래스를 함께 동작할 수 있도록 해주는 구조적인 패턴이다. 이 패턴을 사용하면 인터페이스 호환성 문제를 해결하고 코드를 보다 모듈화하고 유연하게 만들 수 있다.
public interface UserRepository {
List<User> findByUsers(String a, String b, String c);
User findById(Long userId);
}
@Component
@RequiredArgsConstructor
public class UserRepositoryAdapter implements UserRepository {
private final JpaUserRepository jpaUserRepository;
private final QueryDslUserRepository queryDslUserRepository;
@Override
public List<User> findByUsers(String a, String b, String c) {
return queryDslUserRepository.findByUsers(a,b,c);
}
@Override
public User findById(Long userId) {
return jpaUserRepository.findById(userId);
}
}
@Service
@RequiredArgsConstructor
public class UserService{
private final UserRepository userRepository;
public User getUserById( ....) {
return userRepository.findById(...);
}
}
public interface JpaUserRepository extends JpaRepository<User,Long>{
}
public class QueryDslUserRepository {
}
실제로 Adapter를 적용하면 관리해주는 Adapter로 인해 코드의 변경이 유연해지고 안정성은 높아진다. 그러나 구조가 더 복잡해지고 훨씬 더 많은 코드를 작성해야한다..
반면에 어댑터를 제거하고 구조를 단순하게 가져가면 DI와 OCP를 포기하게 된다. 하지만 코드의 생산성 측면이나 구조면에서 간단하기에 오히려 보기좋은 코드가 될 수 있다.
실제로 구현을 해보니 어떤 선택을 하든, 상황에 따라 괜찮은 결정이 될 수 있을 것 같다. 예를 들어, 구조적으로 확장성이 중요한 상황이라면 구조의 안정성이 더욱 중요할 것이니 Adapter를 적용하고 개발의 편의성과 생산성이 중요하다면 적용하지 않는 것이 좋을 것 같다.