- Spring Framework에서 Service와 ServiceImpl 구조를 사용하는 이유는 무엇일까?
1. 인터페이스와 구현 클래스를 분리할 수 있다.
이를 통해 코드의 유연성과 확장성이 증가하며, 유지보수성이 향상된다. Service 인터페이스는 비즈니스 로직을 담당하고, ServiceImpl은 Service 인터페이스를 구현하여 실제 로직을 처리한다.
이를 통해 비즈니스 로직과 구현 로직을 분리함으로써 각각을 독립적으로 개발하고 테스트할 수 있게 된다.
이는 또한 향후 구현 변경이 필요한 경우 인터페이스만 수정하면 되므로 유지보수성이 높아지는 장점이 있다.
2. 스프링 프레임워크가 제공하는 IoC(Inversion of Control) 기능과 함께 사용할 수 있다.
스프링은 IoC 기능을 통해 객체 생성과 의존성 주입을 관리하며, 이를 통해 객체 간의 결합도를 낮추고 유연성과 확장성을 높일 수 있다.
Service와 ServiceImpl 구조를 사용하면 Service 인터페이스를 빈으로 등록하고, 이를 ServiceImpl에서 의존성 주입받아서 사용하는 방식으로 구현할 수 있다.
이를 통해 의존성 주입을 스프링이 관리하도록 만들어 IoC를 구현할 수 있다.
3. 과거의 관습이 현재까지 이어져왔다.
과거 2.0 Spring에서는 AOP Proxy를 구현할 때 JDK Dynamic Proxy를 사용했다.
JDK Dynamic Proxy는 인터페이스를 구현한 객체에 대해서만 AOP Proxy를 생성할 수 있었다.
그러나 시간이 지나면서 인터페이스를 구현하지 않은 클래스에 대해서도 AOP Proxy를 생성할 수 있는 CGLIB가 포함되면서 인터페이스-구현체 관계가 아닌 클래스에 대해서도 AOP 구현이 가능해졌다.
- 그렇다면 Serivce ServiceImpl 구조를 사용하지 않는 이유는? 1. 불필요한 추상화 service와 serviceImpl 구조를 사용하면 인터페이스와 구현 클래스 간의 불필요한 추상화가 추가된다. 이 경우, 단순한 기능을 가진 서비스에서도 인터페이스와 구현체를 생성해야 하므로 코드의 복잡도가 증가할 수 있다. 2. 중복 코드 발생 단순한 CRUD 기능을 수행하는 경우에는 인터페이스와 구현체를 생성하지 않아도 충분하다. 이 경우, Service 인터페이스와 ServiceImpl 구현체를 모두 생성하면서 중복 코드가 발생할 수 있다. 3. 테스트의 어려움 Service와 ServiceImpl 구조를 사용하면 단위 테스트가 어려울 수 있다. 이 구조를 사용하면 Service 인터페이스와 ServiceImpl 구현체를 모두 생성해야 하므로 테스트 코드를 작성하기 어렵다. 또한, 구현체와 인터페이스 간의 의존성이 높아져 테스트 케이스 작성이 복잡해질 수 있다.
Service ServiceImpl 구조를 사용해야 할까?
OOP 관점에서 봤을 때 인터페이스는 다형성 혹은 개방 폐쇄 원칙 때문에 사용한다. 보통 흔히 얘기하는 느슨한 결합 혹은 유연해지도록 설계하기 위해 사용된다. 그렇다면 Spring에서 Service는 다형성이 필요한가..? 본인 경험으로 보았을 땐 다형성이 필요 없는 경우가 대부분이었다. 우리가 사용하는 대부분의 Service는 하나의 Service가 여러 개의 SerivceImpl을 가지고 있는 경우가 아닌 1:1 구조를 띄고 있다. 그러므로 Service를 사용하고, 추후 다형성이 필요해지면 그때 해당 Service에 대해서 인터페이스를 적용해도 늦지 않는 것 같다.