Impl을 그냥 값 return 시키는 용도로만 알고 있다가
너무 뭘 모르는 것 같아서 왜 이렇게 프로젝트를 구성하는지 찾아보았다.
Impl을 설명하는 여러 글들을 찾아본 결과
인터페이스
와 각 서비스 인터페이스에 대한 구현체 클래스
로 이루어진
관습적인 추상화 구조
였다는 답을 얻을 수 있었다.
Impl과 이를 활용한 추상화 구조에 대해 알게 된 것들을 더 정리해 보면서
현재 진행 중인 프로젝트의 구조를 더 잘 이해해보고자 한다.
여기서 관습적인 추상화 구조라는 제목의 의미 부터 알아야 한다.
관습이라 한 이유는 대부분의 스프링 프로젝트에서 Servcie나 DAO를 구현 할 때,
service.java를 인터페이스로, serviceImpl를 구현체 클래스로 만들어서 사용하기 때문이다.
ex) errorCodeService.java / errorCodeServiceImpl.java
ex) errorCodeDAO.java / errorCodeDAOImpl.java
다형성
개방-폐쇄의 원칙
인터페이스를 사용하면 특정 기능에 대한 변경사항이 있을 시,
이를 쉽게 변경할 수 있다. 구현체를 수정하더라도
다른 코드에 영향을 주지 않기 때문이다.
즉, DAOImpl, ServiceImpl에 코드 수정을 하더라도(확장엔 열려있고)
컨트롤러나 그 외 코드를 수정할 필요가 없다는 것이다.(변경엔 닫혀있는)
거창하진 않지만 예시를 들어보겠다.
SomthingDAOImpl.java
public class SomethingDAOImpl implements SomethingDAO {
@Override
public List<SomeDTO> selectSomethingList(SomeDTO somes) throws Exception {
return sqlSession.selectList(namespace+".selectSomethingList", somes)
}
}
SomthingServiceImpl.java
public class SomethingServiceImpl implements SomethingService {
private SomethingDAO somthingDAO;
@Override
public List<SomeDTO> selectSomethingList(SomeDTO somes) throws Exception {
return somthingDAO.selectSomethingList(somes)
}
}
대애충 이정도의 DAO 구현체와 Servcie 구현체가 있다고 치자.
여기서 DAOImpl의 return 값을
...
sqlSession.selectList(namespace+".selectAnythingList", somes)
...
이렇게 바꾸어도 ServiceImpl의 내용은 바꿀 필요가 없다는 것이다.
왜냐하면 Dao내에 있는 메소드를 가져와 리턴하는 것이기 때문에
DAO 구현체가 어떻게 변경이 되든 ServiceImpl는 잘 바뀐 값만 들고와서 리턴해주면 되는 것이다.
Impl을 적용한 프로젝트 대부분은 인터페이스와 구현체가 1:N 관계가 아닌
1:1일 것이라고 한다.
인터페이스를 만드는 이유가 이를 이용하여 코드의 확장성과 재활용성을 높이기 위함인데, 당장 내가 속한 프로젝트도 1:1이다.
그럼에도 이런 구조를 지향하는 이유는
(예전부터 이렇게 해왔으니까라는 이유가 80%인 것 같지만)
1:N의 관계가 나올 가능성을 염두하지 않을 수 없기에 이같은 형태가
관습적으로 굳어진 것 같다.
References
1. 관습적인 추상화 Service, ServiceImpl 구조를 사용해야 할까?
https://wildeveloperetrain.tistory.com/49