1. 관심사의 분리 Separation of Concerns
YoilTeller 프로그램을 보면
으로 나눌 수 있다.
"입력", "처리", "출력"을 Concern(관심사)라 한다. 관심사는 처리할 작업단위라 생각하자. YoilTeller의 main 메서드는 3개의 Concern이 있다.
OOP의 5가지 설계원칙이 있고, 5가지의 앞 글자만 따서 SOLID라 한다. 한 가지가 단일책임의 원칙(SRP, Single Responsibility Principle)이다. 하나의 메서드는 하나의 책임만 가져야 한다는 뜻이다. 여기서 책임은 Concern이고 YoilTeller의 main 메서드는 3개의 Concern이 있어 분리하는 것이 맞다.
객체지향적으로 코딩을 잘하려면 코드 분리를 잘해야 한다. 분리의 종류에는 1. Concern의 분리, 2. Common, Uncommon(변하는 것, 변하지 않는 것)의 분리, 3. 공통(중복) 코드의 분리 3가지가 있다.
따라서 객체지향적으로 프로그래밍하기 위해 main 메서드에서 Concern을 분리할 것이다.
2. 공통 코드의 분리 - 입력의 분리
주황색 박스가 Controller이고 대부분의 Controller가 입력, 처리, 출력으로 구성되어 있다. 입력에서 getParameter 메서드를 중복 사용하므로 각 Controller에서 입력만 빼서 공통으로 쓸 수 있게 앞에다가 두면 각 Controller는 입력이 없어도 된다. 클라이언트에게 요청을 받았을 때 입력을 먼저 처리하고 해당 Controller에 전달하게 된다.
main 메서드의 매개변수를 HttpServletRequest 객체로 받고 getParameter 메서드를 사용해서 꺼내와 썼다. 입력 Concern을 분리하면 request 객체로 받지 않고 개별 매개변수로 직접 받도록 바꿀 수 있다. 차이점은 request 객체 전체를 받아서 썼는데 개별적으로 받을 수 있다. 이렇게 되면 getParameter 메서드를 사용하지 않아도 된다.
심지어는 변수에 String이 아니라 int를 쓸 수 있다. Spring이 문자열을 정수로 자동 형변환 해준다. "abc"은 자동변환되지 않지만 숫자는 자동 형변환해서 쓸 수 있다. 메서드의 선언부를 위와 같이 사용하면 입력 부분 전체가 필요 없다. 공통 코드 중 입력을 분리해서 3개의 Concern 중에 1개가 없어졌다.
3. 출력(view)의 분리 - 변하는 것과 변하지 않은 것의 분리
"입력", "처리", "출력" 중 "입력"을 분리했고 나머지의 Concern을 어떻게 분리하면 좋을지 생각해 보자.
"처리", "출력" Concern이 메서드 안에 같이 있기 때문에 year, month, day, yoil은 바로 접근할 수 있다. 하지만 분리되었을 때는 서로 다른 영역으로 접근하지 못한다. 따라서 이 중간을 이을 객체가 필요하다. 이 객체를 Model 객체라 하고 결과를 출력할 때 필요한 값을 Model 객체에 저장한다. Model 객체를 출력하는 곳에 전달해 원하는 정보를 출력 가능하게 만든다.
"처리" Concern을 Controller, "출력" Concern을 View, Controller와 View 사이의 Data를 주고받게 하는 객체가 Model다. Controller, View, Model 앞글자를 따서 MVC 패턴이라 한다.
코드를 분리하는 과정을 다시 살펴보면
1. main 메서드에서 "입력"을 분리한다.
2. 나머지 "처리", "출력" Concern을 분리한다.
3. Data를 주고받을 Model이 필요하다.
Spring MVC에서는 사용자의 request가 들어오면 DispatcherServlet에서 입력을 처리한다. DispatcherServlet에서 입력을 처리하고 요청을 Controller에 전달한다. Controller가 처리하고 되돌려준 다음 출력에 전달한다. 이때, 입력을 처리하고 Model 객체를 Controller에게 전달하면 처리한 결과를 Model에 저장한다. DiapatchServlet이 작업결과가 담긴 Model을 View에게 전달한다. 이 작업 결과를 응답으로 만들어 클라이언트에게 전달한다.
Spring MVC는 간단하게 이런 구조로 되어 있다. 요약하면 DispatcherServlet에서 입력처리를 하고 결과를 저장할 Model과 함께 Controller에게 전달한다. Controller가 처리를 하고 결과를 Model에 저장하면 이것을 View에게 전달하고 최종적으로 응답을 만들어서 클라이언트에게 전달한다. 실제로는 이보다 더 복잡하다.
4. MVC 패턴
요청이 들어오면 DispatcherServlet이 입력, 변환을 자동으로 처리하고 Model 객체를 생성한다. Model은 결과를 저장할 저장소이고, Controller에게 전달해서 처리한다. 위 코드를 보면 '// 1. 유효성 검사'가 있는데, 날짜가 유효하지 않을 경우 Error를 출력한다.
Controller가 입력받은 날짜로 yoil을 계산한다. 이 결과는 Model 객체에 key, value 형태로 담아진다.
DispatcherServlet가 Model을 View에게 전달을 하기에 앞서 Controller가 어떤 View에게 전달할지 return에 작성할 수 있다. return "yoil"이라 적으면 yoil.jsp를 통해 결과를 보여주라고 전달한다.
"yoil"이 View의 이름인데 타입이 String이기 때문에 기존의 void에서 String으로 바꿔야 한다. 또한 Model을 매개변수로 받아야 하므로 Model model이 추가되었다. 이는 Servlet에서 HttpServletRequest request와 같은 맥락이다.
DispatcherServlet이 매개변수의 Model model을 보고 new Model( ); 객체를 만들어서 넘겨준다. 따라서 Controller는 작업결과를 넘겨받은 Model에다가 저장하기만 하면 된다. 따로 Model을 넘길 필요가 없고 return에 어떤 View로 작업할지만 적으면 된다.
⭐ Controller는 Model에 담기만 한다.
⭐ 작업 결과를 보여줄 View의 이름을 반환한다.
Model을 yoil.jsp에 전달하고 최종 결과물은 Model에 저장했던 결과물로 채워져 클라이언트에게 보인다.
yoil이 유효하지 않으면 return "yoilError"을 반환해서 yoilError.jsp가 클라이언트에게 응답을 전달하다. 이때, Model은 필요하지 않다. yoil.jsp, yoilError.jsp가 View인데 View를 Controller에서 분리하니 상황에 따라서 보여줄 것을 다르게 할 수 있다.
은행에서 1년치 거래내역을 조회를 했을 때, 보일 형식 pdf, CSV, excel으로 버튼을 만들면 각각이 View가 된다. 1년 치년치 거래내역이 Model인데 이 Model이 사용자가 선택한 View에 맞게 data를 전달 받을 수 있게 한다. 이 예시가 MVC패턴을 잘 분리한 예이다.
'스프링의 정석 > Ch. 02 Spring MVC' 카테고리의 다른 글
ch2_10. 관심사의 분리와 MVC패턴 - 실습(2) (0) | 2023.07.05 |
---|---|
ch2_10. 관심사의 분리와 MVC패턴 - 실습(1) (0) | 2023.04.12 |
ch2_08. 텍스트와 바이너리, MIME, Base64 (0) | 2023.04.12 |
ch2_07. HTTP 요청과 응답 - 이론(1) (0) | 2023.04.12 |
ch2_06. 설정 파일 - server.xml, web.xml (0) | 2023.04.12 |