프로젝트를 진행하면서 코드를 짜면서 여러 코드를 찾아보던 중, 대부분의 코드가 Service 인터페이스와 ServiceImpl 구현체로 나눈다는 것을 알게 되었다.
굳이 인터페이스 없이 바로 Service 코드를 작성해도 문제가 없지 않을까라는 의문점이 들게 되었다.
결론부터 말하자면 테스트 용이성과 다양성, 확장성 그리고 유지보수성을 높이기 위해서이다.
인터페이스를 사용한다면 Mock 객체를 만들어서 테스트 환경에서 실제 구현체를 대체할 수 있기 때문이다.
public class MockUserService implements UserService {
@Override
public User findUserById(Long id) {
return new User(id, "testUser", "test@example.com");
}
}
이런 식으로 코드를 짜면 실제 DB에 접근하지 않고 테스트를 진행할 수 있다.
인터페이스를 사용한다면 하나의 서비스에 대해 여러 구현체를 만들 수 있다.
public interface PaymentService { // Paymant 인터페이스
void processPayment();
}
구현체 1
public class CreditCardPaymentService implements PaymentService {
@Override
public void processPayment() {
System.out.println("Processing credit card payment...");
}
}
구현체 2
public class PayPalPaymentService implements PaymentService {
@Override
public void processPayment() {
System.out.println("Processing PayPal payment...");
}
}
서비스 교체가 필요한 경우엔 인터페이스를 통해서 쉽게 구현체를 변경할 수 있다.
인터페이스를 사용한다면 새로운 기능이 추가될 때 기존의 코드를 최소한 변경하면서 확장할 수 있다.
public interface UserService {
User findUserById(Long id);
List<User> findAllUsers(); // 새로 추가된 메서드
}
기존 구현체는 추가된 메서드만 구현하면 되므로 변경 범위가 제한이 된다.
대부분의 프로젝트와 예제 코드에서 인터페이스와 구현체가 나뉜다고 똑같이 만들지 말고 그렇게 나누는 패턴을 사용하는 이유에 대해서 알고 진행하는게 좋을거 같다.