이전까지는 왜 굳이 service를 interface와 impl로 분리하는지 몰랐고, 그냥 팀원이 하니까 무지성으로 따라했고, 혼자 프로젝트를 할때에는 하나의 인터페이스와 하나의 구현클래스 만 쓰기때문에 무의미하다 생각하여 분리하지 않았다.
인터페이스와 구현체 클래스를 분리함으로써 구현체를 독립적으로 확장할 수 있으며, 구현체 클래스를 변경하거나 확장해도 이를 사용하는 클라이언트의 코드에는 영향을 주지 않는다.
추상화를 통한 구현 방식은 객체 지향의 특징 중 하나인 다형성과 객체지향의 다섯가지 원칙 중 하나인 OCP 원칙을 가장 잘 실현해주는 설계 방식이라고 할 수 있다.
개방-폐쇄 원칙(OCP, Open-Closed Principle) : '소프트웨어 개체(클래스, 모듈, 함수 등)는 확장에 대해 열려 있어야 하고, 수정에 대해서는 닫혀 있어야 한다'는 프로그래밍 원칙
확장성을 보장하기 위해서는 개발자는 언제든지 구현 로직이 변경될 수 있음을 염두에 두어야 하며, 분리된 구조를 적용하면 하나의 인터페이스에 대해 여러 개의 독립된 구현체를 사용할 수 있다는 장점을 갖는다. 이는 모듈 개발과 배포 단계에서 각각 다른 로직을 구성할 수 있음을 의미한다. 또한 이는 구현체와 인터페이스를 명확히 구분함으로써 유연성을 확보한다.
MVC 패턴에서는 View가 자신이 요청할 Controller만 알고 있으면 되며, Controller는 화면에서 넘어오는 매개변수들을 이용해 Service 객체를 호출하는 역할을 수행한다. 그렇기에 Service는 어떤 컨트롤러에서 호출되더라도 필요한 매개변수만 받아들여 자신의 비즈니스 로직을 처리할 수 있다. 이는 모듈화를 통해 재사용 가능한 클래스 파일을 만들어내며, View가 변경되더라도 Service는 그대로 유지되어 재사용할 수 있는 장점을 가진다.
더불어, Service는 순수한 자바 객체로 구성되어 있어서 웹 기반 뿐만 아니라 추후에는 네이티브 앱으로의 전환이 이루어져도 View에 종속적인 코드가 없기 때문에 그대로 재사용이 가능합니다. 새로운 요청사항이 발생하더라도 기존 소스를 수정하는 것이 아니라 기존 service 인터페이스를 구현한 다른 클래스를 만들어 해당 객체를 사용하도록 하는 방식으로 확장성을 확보할 수 있습니다.
Model: 애플리케이션의 데이터와 비즈니스 로직을 담당. 데이터베이스와 상호작용하거나 데이터를 처리하는 등의 역할을 수행
View: 사용자에게 데이터를 표시하고 사용자의 입력을 받는 역할. 주로 사용자 인터페이스(UI)를 담당
Controller: 사용자의 입력을 받아 해당하는 작업을 수행하고 모델의 데이터 또는 뷰를 업데이트하는 역할
Entity의 경우 이미 DTO가 존재하여 데이터 전송 객체와의 매핑이 되어있고, 컨트롤러는 사실상 디스패처 서블릿을 통해 요청을 처리하므로 직접 작성하지 않지만 분리되어 있다.
Repository는 데이터 JPA를 활용하고 있어서 데이터 액세스 레이어의 인터페이스 작업이 필요하지 않았다.
프로젝트에서 코드를 분리하면 코드 구조가 복잡해지고, 복잡해진 구조 만큼 코드를 분석하고 확인하는 과정에서 인터페이스를 거쳐 구현체들을 확인해야 하는 번거로움이 생긴다. 하지만 Service, ServiceImpl 패턴으로 설계를 해야하는 이유는 인터페이스와 구현체를 분리함으로써 구현체를 독립적으로 확장할 수 있으며, 구현체 클래스를 변경하거나 확장해도 영향이 최소화된다. 이는 JAVA 언어를 쓰는 가장 큰 목적인 객체지향의 특징을 잘 실현해주는 설계방식이다.
참고한 글
https://wildeveloperetrain.tistory.com/49
https://multifrontgarden.tistory.com/97
https://velog.io/@ghkdwp018/service를-interface와-impl로-분리하는-이유