SSAFY11th-book-study / book-study

SSAFY 11기 6반의 '토비의 스프링 스터디'
0 stars 0 forks source link

[1.7] 인터페이스가 아닌 구현체 클래스를 DI #11

Closed hj-k66 closed 7 months ago

hj-k66 commented 7 months ago

116p에서 의존관계 주입의 조건에서, 클래스 모델이나 코드에는 런타임 시점의 의존관계가 드러나지 않는다. 그러기 위해서는 인터페이스에만 의존하고 있어야 한다. 라고 설명하고 있습니다.

하지만 인터페이스와 구현체 클래스 사이의 관계가 1대1인 경우, 구현체 클래스 자체를 DI할 때가 있는 것 같습니다. 예를 들어 저는 주로 스프링 MVC 구조로 구현할 때 Controller에 Service를 DI할 때, 위 설명처럼 Serivice 인터페이스에 의존하는 것이 아닌 Service 클래스를 의존하게 해왔습니다. 왜냐하면 대부분의 프로젝트에서 Service의 인터페이스와 구현체 클래스는 1:1로 만들어져 사용되기 때문에 인터페이스의 필요성을 못 느꼈기 때문입니다.

@Service
public class UserService{
   ...
}

@RestController
public class UserController{
    private final UserService userService;

   @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    public ResponseEntity<Void> deleteUser(String id){
          userService.delete(id);
         .....
   }
}

물론 관습적으로 Service 인터페이스를 만들고 ServiceImpl로 구현체를 만드는 경우도 있는데, 다들 평소에 어떻게 하시는지, 인터페이스가 아닌 구현체 클래스를 DI를 하는 것에 대한 의견들이 궁금합니다!

sootudio commented 7 months ago

제가 찾아봤을 때는, 질문에 올라온 상황처럼 한 인터페이스에 대응하는 구현체가 하나밖에 없는 경우나, 인터페이스와 그 구현체가 밀접하게 연관되어 있을 때는 구현체를 직접 DI하는 것이 더 간단할 수 있다고 이해했습니다.

그러므로 책에서

클래스 모델이나 코드에는 런타임 시점의 의존관계가 드러나지 않는다. 그러기 위해서는 인터페이스에만 의존하고 있어야 한다.

라고 한 것은 강제적이라기 보다는 일반적인 권장사항을 조금 강한 어조로 말한거라고 생각이 드네요,,,

다만, 제가 스프링 프로젝트를 해 보지 않아서 모르는 것일 수도 있는데, 질문에 올려주신 Service의 예시처럼 인터페이스와 구현체 클래스가 1:1 인 경우, 추가적으로 구현체가 만들어져야 하는 상황은 거의 없나요?

제가 생각했을 때는 해당 상황에서 새로운 구현체 클래스가 만들어질 경우(ex. AdminUserService 클래스라던지...) UserController를 수정해야 한다고 생각했는데, 대부분의 스프링 프로젝트에서 Service 인터페이스와 클래스의 관계가 1:1 이라면, 제가 생각하는 상황이 거의 일어나지 않을 것 같아서요!

limjongheok commented 7 months ago

사실 저 같은 경우에는 Impl 형식으로 인터페이스를 만들고 구현체를 만드는 방식을 많이 사용을 했었는데 인터페이스 방식이 아무래도 ocp 적으로 확장및 변경에 있어 자유롭지 않나 하고 많이 썼던 것 같습니다.
허나 해당 이슈에 대해 블라인드등 많은 토론이 있다 보았는데 제가 본 것 들 대부분도 어차피 서비스와 컨트롤러간 1:1 관계이니 불필요한 계층 구조가 필요 없다 라는 형식을 많이 본거 같습니다. 제가 찾아 본거로는 인터페이스는 과거 Spring이 AOP 를 구현 할때 JDK Dynamic Proxy를 사용하는데 JDK Dynamic Proxy는 프록시 객체를 생성하려면 인터페이스가 필수 였는데 (@Transactional 어노테이션 등이 동작 하기 위해서는) 그러나 시간이 지나면서 Spring 3.2 부터는 CGLIB를 기본적으로 포함하여 클래스를 기반으로 프록시 객체를 생성할 수 있다고 하네요 즉 과거 Spring 에서는 필수적으로 사용을 해야 했었는데 지금은 사용을 안해도 되는 것 같습니다.

허나

public interface MemberService{}
public class AdminUserService implements MeberService{}
public class GeneralUserService implements MeberService {}

다음과 같이 권한 마다 구현이 다른 Service 같은 경우 인터페이스 활용이 좋다고 생각 듭니다.

hj-k66 commented 7 months ago

interface를 사용했을 때 장점

  1. 테스트하기 편함.
  2. 가독성