본문 바로가기

SpringBoot

ch2 06. MVC로 관심사를 분리하기 (1) - 실습

1. 관심사의 분리 Separation of Concerns

- 이 메소드 하나는 3개의 관심사를 가지고 있다. 

-> 하나의 메소드 내에 너무 많은 관심사가 있는 것!  ->'분리'가 필요하다.

 

" 하나의 메소드는 하나의 관심사만"

 

* 코드의 분리
1) 관심사

2) 변하는 것과 변하지 않는 것

3) 중복 코드 - 별도의 메소드를 만들어서 중복 코드를 제거해야 한다. 

 

OOP를 사용하는 주요 목적은 '변경에 대비하는 코드'를 작성하는 것. 

 

예제의 작업 날짜를 계산하는 부분은 '잘 변하지 않는 부분'

html이 들어있는 부분은 '자주 변경될 수 있는 부분'

-> 이 두 코드는 별도의 메소드로 구분되어야 한다. 

 

 

2. 단일 책임 원칙 SRP, Single Responsibility Principle

- 객체지향 설계 5대 원칙 - SOLID

1. 단일 책임 원칙(SRP, Single Responsibility Principle)

- 하나의 메소드는 하나의 책임만 갖는다. (책임 => Concern 관심사) -> 예제의 메소드는 SRP를 위반한 것 ! 

 

2. 개방 폐쇄 원칙(OCP, Open-Closed Principle)

- 상속에는 Open, 변경 Closed 

- 코드를 변경할 상황이 있다면, 기존 코드를 변경하지말고 상속을 통해서 변경하라. (Overriding)

 

3. 리스코프 치환 원칙(LSP, Liskov Substitution Principle)

- 같은 조항의 다른 클래스로 바꿔도 동작해야 한다. (다형성 관련)

 

4. 인터페이스 분리 원칙(ISP, Interface Segregation Principle)

- 유사한 인터페이스라도 목적이 다르면 분리해야한다. 

 

5. 의존관계 역전 원칙(DIP, Dependency Inversion Principle)

- 추상화 관련. 코드를 추상화에 의존한 코드를 작성해야 한다. 

- 코드가 너무 구체적이면 '변경에 불리'하기 때문에 덜 구체적인 추상화된 코드를 작성해야 '변경에 유리'해진다. 

 

 

3. 공통 코드의 분리 - 입력의 분리 

- 예제 YoilTeller처럼 사용자의 요청을 받아서 처리하는 메소드들은 주로 세가지 일을 한다. 

1) 입력 - 요청을 받음
2) 처리
3) 출력 - 출력해서 응답

메소드가 여러 개 있을 때 관심사가 너무 많다.(3개의 관심사) 

- 입력은 request.getParameter를 이용해서 읽어온다.
그래서 이걸 각 메소드에서 처리하지 않고, 별도의 메소드에서 '입력'만 처리할 수 있도록 분리한다.
(하나의 관심사를 분리)

Spring에서는 DispatcherServlet이 있어서 모든 요청을 DispatcherServlet이 다 요청을 받는다. 
그래서 입력을 처리한 다음 그걸 각각의 메소드에게 전달해준다. 

-> 입력 처리하던 코드들이 줄어들고 관심사도 줄어들면서 코드 관리가 더 쉬워지게 된다. 

 

<매개 변수로 받을 데이터를 직접 선언해준다>

- request.getParameter() 대신에 매개변수로 선언해주는 것. (대신에 요청에서도 이름이 일치해야 한다.)

- Spring이 알아서 해당 값들을 찾아서 넣어준다.
-> Reflection API가 존재하기 때문(Java 기본 제공 API) . 이걸 이용하면 이 메소드에 대한 정보를 다 얻어올 수 있게 되며,
이 메소드의 매개변수가 뭔지 다 보고 getParameter()에서 하던 것들을 이름을 보고서 자동으로 이 값들을 읽어서 
매개변수로 넣어준다. 

 

 

<Spring의 장점은 여기서 String을 int로 자동 변환을 수행해주기 때문에 다음과 같은 코드도 가능하다> 

매개 변수 타입을 String이라고 안쓰고 int라고 쓰면 Spring이 알아서 변환도 수행해준다. 

그래서 변환하는 코드도 사용하지 않아도 된다. 

 

 

(관심사의 분리를 수행했지만, 아직 2개의 관심사가 남아있다)

4. 출력(view)의 분리 - 변하는 것과 변하지 않는 것의 분리

- 2개의 관심사(SRP 위반. 잘 변하지 않는 부분 / 자주 변하는 부분 -> 분리가 필요하다.)

 

- 원래는 전달할 필요가 없었는데, 별도의 메소드로 분리하게 되면 처리 부분에서 작업한 결과를 출력으로 전달해야 한다. 

값이 여러개이기 때문에 객체(Model)에 담아서 전달해준다. (처리 부분은 Controller)

모델에 담겨있는 실행 결과를 보여주는 부분을 View라고 한다. (MVC 패턴)

 

 

5. MVC 패턴

(1) 요청

- 사용자로부터 요청이 오면, DispatcherServlet이 모든 요청을 다 받는다. 

1) 입력 부분(request.getParameter 처리) & 변환(String -> int로 변환 등)

2) 모델 생성(View에 전달할 data를 담을 객체)

 

(2) 컨트롤러 메소드에 Model을 선언하면 DispatcherServlet이 모델 객체를 생성해서 넘겨준다.(객체의 주소를 줌)

 

(3) 메소드에서는 작업을 수행한 다음 그 작업 결과를 model에 저장. 

그리고 이 작업 결과를 어떤 view를 통해서 보여줄지를 알려줘야 한다. 
(원래는 yoil은 경로에 있는 yoil.html을 의미하지만 thymeleaf로 작성된 파일. html이 확장자지만 thymeleaf라는 
템플릿을 이용해서 html을 작성한 것. thymeleaf는 템플릿 엔진으로 Java의 JSP와 비슷하며, JSP보다 편한 점이 
많으며 Spring boot에서는 thymeleaf가 기본 템플릿 엔진이다.

원래는 System.out으로 다 출력하는 것인데 그 부분을 따로 떼어내서 별도의 파일로 만들어버린 것)

 

(4) 객체를 View에게 전달

 

(5) View가 DispatcherServlet으로부터 전달 받은 모델에서 값을 꺼내서 출력하는 것이다. 

 

=> SRP 원칙을 지킨 코드 완성

 

 

6. ModelAndView(모델과 뷰를 하나의 객체에 담아서 넘겨준다.)


- 많이 쓰지는 않지만 존재. 

- 앞 예제에서는 DispatcherServlet이 모델 생성을 해서 넘겨줬는데, ModelAndView에서는 컨트롤러에서 모델을 생성한다.
- 어떤 뷰를 쓸건지 뷰를 지정한다. (뷰에 대한 정보가 들어있다)

=> 이 두개의 정보를 DispatcherServlet에게 제공해야 하는데, 이 두 개를 묶은 것이 ModelAndView이다. 
그래서 반환 타입이 ModelAndView이다. 

그러면 DispatcherServlet이 모델과 뷰 이름을 같이 받고, 성공했을 경우 yoil.html을 이용해서 모델에 담겨있던 데이터를

읽어서 보여준다. 

 

 

7. 컨트롤러 메소드의 반환타입

1) [String] 뷰 이름을 반환
- 기본적으로 많이 사용. 뷰의 이름을 반환

- 이 메소드에서 작업을 수행한 결과를 어떤 뷰를 통해서 보여줄 것인지 지정해줘야 한다. 

 

2) [void] 맵핑된 url의 끝단어가 뷰 이름

- 메소드의 반환 타입이 void인 경우 url을 가지고 뷰 이름을 판단한다. 

 

3) [ModelAndView] Model과 뷰 이름을 반환

 - 컨트롤러에서 Model을 생성하는 경우 사용. 뷰 이름을 지정 => 두 개의 정보를 합쳐서 DispatcherServlet에게 리턴