
프로젝트 코드를 보면, 패키지 명에 Service / ServiceImpl 로 나누어 작성한 모습을 볼 수 있습니다.
원래 인터페이스는 자바의 객체지향적 특징중 하나인 다형성(OCP)을 위해 사용하지만, 여기서는 심지어 1:1 관계입니다.
일반적인 토이 프로젝트에서 굳이 이렇게 나누어야 하나? 라는 생각이 들어 이 글을 작성하게 되었습니다.
사실 굳이 이렇게 나누지 않아도 됩니다.
위에서 언급하였듯 작은 프로젝트 구조에서는 굳이 이렇게 나눌 필요가 없습니다.
그렇다면 왜 나누어서 작성하는걸까?
인터페이스와 구현체를 분리하여 얻을 수 있는 장점은 구현체 클래스를 변경하거나 확장해도, 이것을 호출하는 부분에는 영향을 주지 않는다는 것입니다.
// 컨트롤러
public class ClubController {
private final ClubService clubService;
@Operation(summary = "모든 모임 리스트 조회")
@GetMapping
public ApiResponse<?> getClubList(ClubPageRequestDTO pageRequestDTO) {
return ApiResponse.ok(clubService.getAllClubs(pageRequestDTO));
}
}
// 인터페이스
public interface ClubService {
PageResponseDTO<ClubResponseDTO> getAllClubs(ClubPageRequestDTO pageRequestDTO);
}
// 구현체
public class ClubServiceImpl implements ClubService {
@Override
public PageResponseDTO<ClubResponseDTO> getAllClubs(ClubPageRequestDTO pageRequestDTO) {
Page<ClubResponseDTO> result = clubRepository.findAll(pageRequestDTO);
return PageResponseDTO.<ClubResponseDTO>withAll()
.pageRequestDTO(pageRequestDTO)
.dtoList(result.toList())
.total(Long.valueOf(result.getTotalElements()).intValue())
.build();
}
}
컨트롤러 : 인터페이스의 코드를 주입받음. 다른거는 상관 안함
인터페이스 : 구현체를 선언함.
구현체 : 코드의 변경이 일어남
실제로 클라이언트쪽 코드에서는 컨트롤러의 API를 가져다 쓰기 때문에, 구현체가 변경되어도 다른부분을 수정할 필요가 없다는 것입니다.
결론은
장점 : 이러한 인터페이스/구현체 구분을 이용하여, 코드의 유연성을 높이고 변화에 용이하게 만듭니다.
단점 : 코드가 복잡해져 분석하고 확인하는 부분에서 불편해질 수 있습니다.