public interface MemberService{
Boolean singUp();
}
public class Member implements MemberService {
@Override
public Boolean singUp() {
return true;
}
}
SpringMVC 구조로 개발 할 때 Service단을 Service, ServiceImpl 즉 인터페이스와 구현체로 구분하여 개발을 했었는데
오픈 소스를 분석하는 도중 Service단을 인터페이스-구현체 구조가 아닌 Service 클래스를 단일로 사용하는 구조가 많이 보였다.
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 구현이 가능해졌다.
- Spring AOP Proxy : 런타임 시점에 원래 객체의 기능을 감싸서 대신 호출하며, 메소드 호출 전후에 공통적으로 수행되어야 하는 로직(Advice)을 삽입합니다. 이러한 AOP Proxy를 사용하여 스프링은 애플리케이션에서 공통적으로 발생하는 문제를 해결하고, 유지보수 및 확장성을 높일 수 있게 해 준다. |
그렇다면 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에 대해서 인터페이스를 적용해도 늦지 않는 것 같다.
'Spring' 카테고리의 다른 글
[SpringBoot] yml, propertise 설정 값 암호화 (Jasypt) (0) | 2023.08.20 |
---|---|
[Spring] Java 문자열 null, 빈값, 공백체크 방법 StringUtils.hasText (0) | 2022.10.19 |