MVC 디자인 패턴
MVC 디자인 패턴
기본적으로 MVC 소프트웨어 디자인 패턴은 ‘화면(사용자 인터페이스)로부터 비즈니스 로직을 분리’하는데 중점을 두고 있다. (이를 ‘관심사 분리‘라고 한다.)
→ 이를 통해 어플리케이션의 시각적 요소나 그 이면에서 실행되는 비즈니스 로직을 서로 영향 없이 쉽게 고칠 수 있게 된다.
MVC 패턴에서는 어플리케이션의 구성요소를 3가지 형태로 나누고 있다. - Model, View, Controller
MVC에서 모델은 애플리케이션의 정보(데이터)를 나타내며, 뷰는 텍스트, 체크박스 항목 등과 같은 사용자 인터페이스 요소를 나타내고, 컨트롤러는 데이터와 비즈니스 로직 사이의 상호동작을 관리한다.
Mozilla에서는 각 구성 요소에 대해 아래와 같이 설명하고 있다.
- 모델: 데이터와 비즈니스 로직을 관리합니다.
- 뷰: 레이아웃과 화면을 처리합니다.
- 컨트롤러: 명령을 모델과 뷰 부분으로 라우팅합니다.
MVC는 위와같은 형태를 띄고 있다.(출처 - mozilla)
- 컨트롤러는 모델에 명령을 보냄으로써 모델의 상태를 변경할 수 있다. 또, 컨트롤러가 관련된 뷰에 명령을 보냄으로써 모델의 표시 방법을 바꿀 수 있다.
- ‘컨트롤러 → 뷰’방향의 명령 예시 - 리스트로 보이는 데이터를 특정값 기준으로 정렬하여 보고자 하는 경우
- 모델은 모델의 상태에 변화가 있을 때 컨트롤러와 뷰에 이를 통보한다. 이와 같은 통보를 통해서 뷰는 최신의 결과를 보여줄 수 있고, 컨트롤러는 모델의 변화에 따른 적용 가능한 명령을 추가·제거·수정할 수 있다. 어떤 MVC 구현에서는 통보 대신 뷰나 컨트롤러가 직접 모델의 상태를 읽어 오기도 한다.
- 뷰는 사용자가 볼 결과물을 생성하기 위해 모델로부터 정보를 얻어 온다. (표시할 데이터를 모델로부터 받아온다.)
그럼 뷰가 어떻게 모델의 데이터를 가져오는가?
이는 전통적으로 Observer패턴을 사용했다.
출처: Apple archive - ‘Concepts in Objective-C Programming’
- 모델은 데이터 변경사항을 알리고 뷰는 이를 관찰하고 있다가 변경사항을 반영한다.
근데 이렇게 Observer 패턴을 사용하면 모델이 뷰를 알고 있는 형태가 되는데, 이렇게 하면 안되는거 아니냐고??
→ 아니다. MVC에서는 이것을 허용하고 있었다. 😅
위키백과 - MVC
하지만 애플 문서에서는 위와 같은 형태가 문제점이 있다고 지적하고 있었다.
- 뷰 객체와 모델 객체는 어플리케이션 내에서 반드시 재사용가능해야 한다.
- 뷰 객체는 운영체제와 시스템이 지원하는 어플리케이션의 “외관과 느낌”을 나타냅니다. 모양과 행동의 일관성은 필수적이기에 높은 재사용성의 객체가 필요한 것은 당연합니다.
- 정의(definition)에 의한 모델 객체는 문제 도메인과 관련된 데이터를 캡슐화하며 해당 데이터에 대한 작업을 수행할 수 있습니다.
- 디자인 측면에서 모델과 뷰 객체를 서로 분리하는 것은 재사용성을 증진시킨다는 측면에서 매우 좋다.
→ 모델이 뷰를 아는 위와같은 상황에서는 뷰와 모델이 분리되어있지 않으므로(의존성이 존재하므로) 재사용성이 떨어진다고 말하고 있다.
그래서 Cocoa에서는 컨트롤러와 뷰 객체에 주어지는 역할에 차이점을 두었다. 바로 아래 그림과 같이 말이다.
근데 찾아보면 요즘에는 다른분야(웹이든 어디든)에서도 ‘뷰와 모델이 서로를 알고 있지 않도록 만들어라’라고 말하고 있긴 하다. (그냥 ‘뷰와 모델은 다른 컴포넌트들을 아예 몰라야 한다’라고 말하고 있음)
→ MVVM 탄생과정, 특징 - 박이얏호 블로그 내용에 따르면 아래와 같은 방식은 Apple이 만들어낸 것이라고 한다.
- 대부분의 Cocoa 어플리케이션에서, 모델 객체의 상태변화 알림은 컨트롤러 객체를 통해 뷰 객체에 전달된다.
위 그림에서의 각 객체 역할과 책임, 커뮤니케이션 방법에 대해 애플 문서에서는 아래와 같이 설명하고 있다.
Model
-
모델 객체는 응용프로그램의 데이터를 캡슐화하며 해당 데이터들을 조작하고 처리하는 로직과 연산을 정의한다.
-
모델 객체는 다른 모델 객체와 일대일 / 일대다 관계를 가질 수 있다. 때때로 응용프로그램의 모델 레이어는 하나 이상의 객체 그래프로 이루어져 있다.
-
응용프로그램의 영구적 상태에 속하는 대부분의 데이터들은 모델 객체에 존재해야 한다.(그것이 파일로 저장되어있든 데이터베이스로 저장되어있든)
-
모델 객체는 뷰 객체와 명시적으로 연결되어있어서는 안된다.
-
Communication
- 뷰 레이어에서 데이터를 생성하거나 변경시키는 사용자 행동은 컨트롤러를 통해 모델 객체의 생성 또는 업데이트를 일으키게 된다.
- 모델 객체가 변경되면 그것은 컨트롤러 객체에 알려지고 컨트롤러 객체는 적절한 뷰 객체를 업데이트한다.
View
-
뷰 객체는 응용프로그램에서 사용자들이 볼 수 있는 부분의 객체를 의미한다.
-
뷰 객체는 뷰를 어떻게 그릴지와 사용자의 행동에 어떻게 응답해야 할지 알고있다.
-
뷰 객체의 주요 목적은 모델 객체의 데이터를 보여주고 이 데이터들을 편집할 수 있도록 하는 것이다.
→ 뷰 객체는 일반적으로 모델 객체와 분리되어있다.
-
Communication
- 뷰 객체는 모델 객체의 변화를 컨트롤러 객체를 통해 알게 된다.
-
사용자에 의해 시작된 변화들은 - 이를테면 텍스트 필드에 텍스트를 넣는다던가 - 컨트롤러 객체를 통해 모델객체에 전달된다.
Controller
-
컨트롤러 객체는 하나 이상의 뷰 객체와 하나 이상의 모델 객체간의 중계자 역할을 한다.
-
컨트롤러 객체는 뷰 객체가 모델 객체의 변화를 알게되는 통로이자 모델 객체가 뷰 객체의 변화를 알게되는 통로이다.
-
또한 컨트롤러 객체는 응용프로그램의 설정 및 조정 작업을 수행하며 다른 객체들의 수명주기(Life Cycle)를 관리하는 역할을 한다.
-
Communication
- 컨트롤러 객체는 뷰 객체에서의 사용자 행동을 해석하여 데이터의 생성이나 변경에 대한 것을 모델 레이어에 알린다.
- 모델 객체에서 변경이 발생하면 컨트롤러 객체는 새로운 모델 데이터를 뷰 객체에게 알린다.(뷰 객체가 새로운 데이터를 보여줄 수 있도록)
MVC의 한계
-
Apple의 MVC는 View와 Controller가 너무 밀접하다.
Apple의 MVC에서는
ViewController
라는 이름에서도 볼 수 있듯이 View와 Controller가 굉장히 밀접하게 연결되어있다. ViewController는 Controller의 역할뿐만 아니라 View의 life cycle에도 관여하고 있는 것이 현실이다. 이때문에 Model은 분리하여 테스트를 할 수 있어도 View와 Controller는 서로 강하게 연결되어있어 테스트가 어렵다. -
뷰, 모델에 맞지 않는 모든 비즈니스 로직들은 Controller에 들어가게 된다.
모델이나 뷰에 넣기 애매한 코드들은 모두 Controller에 들어가게 되는데 이렇다보니 Controller가 비대해질 수 있다.
이를테면 서버에서 받아온 데이터를 가공(포매팅)해서 뷰에 넘겨주는 로직이나 사용자로부터 들어온 interaction을 처리하여 모델/뷰에 넘기는 로직 등, 화면에 보이는 것과 데이터 이외에는 모두 ViewController가 처리하게 된다.
Clint Jang은 MVC의 한계를 아래와 같이 설명해주셨다.
MVC에서 View는 Controller에 연결되어 화면을 구성하는 단위요소이므로 다수의 View들을 가질 수 있습니다. 그리고 Model은 Controller를 통해서 View와 연결되어지지만, 이렇게 Controller를 통해서 하나의 View에 연결될 수 있는 Model도 여러개가 될 수 있습니다.
→ 뷰와 모델이 서로 의존성을 띄게 됩니다.
즉, 화면에 복잡한 화면과 데이터의 구성 필요한 구성이라면, Controller에 다수의 Model과 View가 복잡하게 연결되어 있는 상황이 생길 수 있습니다.
후략…
References
-
코든의 2021년 6월 6일 TIL
댓글남기기