디자인패턴

MVP 패턴

SniKuz 2024. 6. 19. 17:35

목차

 

* 작성중 알게된 포스트로 궁금했던 대부분이 써져있어서 해당 블로그를 보는걸 추천합니다.

https://blog.naver.com/jukrang/221597910488

 

MV-Whatever 정리 - 2. MVP

MVP(Model - View - Presenter)는 MVC를 재해석하며 등장했다. Controller의 자리를 Presenter...

blog.naver.com

 

 

MVP

- 개요

MVC 패턴의 파생으로, 자동화된 유닛테스트를 용이하게 하고 프로젠테이션 로직에서 관심사를 분리하도록 설계된 사용자 인터페이스 아키텍처 패턴입니다.
- MVP Pattern Wikipedia
MVP는 IBM에서 처음 등장하고 1990년대 Taligent에서 더 눈에 띄게 등장한 아키텍처입니다.
Taligent의 CTO였던 Mike Potel의 논문이 가장 일반적으로 참조되었으며, Dolphin Smalltalk 개발자들에 의해 대중화되었습니다. 위 2가지 내용이 완전히 일치하지는 않지만, 그 속에 일치하는 기본 아이디어는 인기있어졌습니다.
- Martin Fowler 

대표적인 MVP 형태를 정리합니다.

 

 

 


- Model - View - Presenter. The Taligent Programming Model for C++ and JAVA (Mike Potel)

MVP란

IBM의 완전 자회사인 Taligent는 Small Talk의 고전적인 MVC 프로그래밍 모델의 일반화에 기초하여 MVP라 불리는 C++,Java 프로그래밍 언어를 위한 차세대 프로그래밍 모델을 개발하고 있습니다.
MVP는 광범위한 응용 프로그램 및 구성 요소 개발 작업을 위한 강력하면서도 이해하기 쉬운 설계 방법론을 제공합니다.
MVP는 또한 여러 클라이언트 / 서버 및 다중 계층 애플리케이션 아키텍처에 걸쳐 적용할 수 있습니다.
MVP를 통해 IBM은 모든 주요 객체 지향 언어 환경에 통합된 개념적 프로그래밍 모델을 제공할 수 있습니다.

 

- MVC

Small Talk는 MVC의 세 가지 핵심 추상화를 사용하여 확인, 텍스트 입력 필드와 같은 GUI 개체를 나타냅니다.
모델은 확인란의 켜짐/꺼짐 또는 텍스트 입력 필드의 텍스트 문자열과 같은 개체의 기본 데이터를 나타 냅니다.
뷰는 모델의 데이터에 엑세스하고 모델의 데이터가 화면에 그려지는 방법을 지정합니다.
컨트롤러는 제스처 및 이벤트 형태의 뷰와의 사용자 상호 작용으로 인해 모델의 데이터가 변경되는 방식을 결정합니다.

프로그래머는 단일 GUI 객체 내에서 3가지 핵심 MVC 개념 간에 사전 정의된 긴밀한 관계를 상속하여 이점을 얻습니다.
여러 요소가 포함된 대화 상자와 같은 보다 복잡한 GUI 개체는 위에서 설명한 것과 같은 다양한 종류의 GUI 개체의 여러 인스턴스로 구성되며 모두 MVC 클래스로 표시됩니다. 궁극적으로 모든 interactive 그래픽 어플리케이션은 MVC를 사용하여 구축됩니다.

- MVP

Taligent의 전반적인 접근 방식은 기본 MVC 개념을 구성 요소로 분해하고 이를 더욱 구체화하여 프로그래머가 보다 복잡한 애플리케이션을 개발하는데 도움을 주는 것입니다. 이 프로세스의 첫 번째 단계는 모델과 뷰 컨트롤러(프레젠테이션)간의 분리를 공식화하는 것입니다. 이는 상황을 데이터 관리(Data Mgmt)와 사용자 인터페이스(UI) 2가지 기본 개념으로 나눈 것 입니다.

Models enable encapsulation (캡슐화) : 깔끔한 분리와 캡슐화를 통해 다양한 이점을 얻을 수 있습니다. 더 빠른 삽입을 위한 연결 리스트, 더 나은 알파벳 검색을 위한 트라이 구조, 다른 프로그램에서 사용할 우편 주소와 같은 필드 추가를 하더라도 수정없이 동일한 프레젠테이션 코드를 사용할 수 있습니다. 또 기본 모델을 다시 구현하지 않고도 여러 프로젠테이션을 만들 수 있습니다.

Models enable persistence (지속성) : 이전 예시들에서는 모델의 데이터가 모델 자체에 저장되었습니다. 그 외에도 모델에는 데이터가 전혀 포함되지 않고 다른 데이터 저장소에서 접근하는 데이터에 대한 프록시(원격 데이터베이스로 이동하는 쿼리 엔진용 코드 등)이 포함되어 있을 수 있습니다.

Models enable sharing (공유성) : 모델을 추상화하면 여러 사용자가 더 유연하게 사용할 수 있습니다. 서로 다른 프로그램 모델이 동일한 원격 데이터를 캡슐화하면 회사 전화번호부처럼 여러 사용자가 동일한 데이터를 공유할 수 있습니다. 공유 데이터 모델에서 새 전화번호 항목이 작성되면 모든 사람이 항상 최신 상태인 반면, 모델이 자체 데이터를 저장하는 경우 모든 사람이 업데이트되어야 합니다.

 

- Three Data Management Questions

Taligent는 데이터관리와 사용자 인터페이스 2가지로 관심사를 분리하여 개발한 여러 프로젝트 경험을 바탕으로 각 관심사를 3가지 하위 질문으로 분해했습니다. 다음은 데이터 관리의 3가지 하위 질문입니다.

1. What is my data? : 캡슐화된 데이터, 읽기 및 쓰기 등을 포함한 SmallTalk(MVC)와 동등한 기본 모델입니다.

2. How do I specify my data : 모델의 데이터에서 다양한 하위 집합을 지정하기 위한 추상화를 Selections라고 합니다.

3. How do I Change my data? : 선택한 모델의 대해 수행할 수 있는 작업을 나타내는 추상화를 Commands라고 합니다.

다음은 그에 대한 예시입니다. 모델이 정수 배열이고 모델의 뷰는 막대 차트일 때 다음과 같은 모습을 띌 수 있습니다.
이 때 뷰는 다른 종류의 뷰일 수 있으며, 꼭 그래픽일 필요는 없습니다. 뷰는 피아노 키보드에 건반이거나, 공장에 특정 밸브일 수 있고, 뷰 없이 모델을 제공할 수도 있습니다.

- Three User Interface Questions

사용자 인터페이스를 어떻게 디자인할지 또한 3가지 질문으로 나눴습니다.

4. How do I display my data? : 지금까지 언급한 뷰입니다. 여러 개의 뷰가 있을 수 있으며 뷰가 시각적일 필요는 없습니다.

5. How do events map into changes in my data? : 이벤트가 데이터 변경 사항에 어떻게 매핑될지에 대한 부분으로, 마우스, 키보드와 같은 상호작용을 Interactor라고 부릅니다.

6. How do I put it all together? : 기존 MVC에서 Controller의 기능을 나타내지만, 이를 Application level로 올리고, Selections, Commands, Interactor의 중간 단계 상호작용 개념을 고려합니다. 이러한 차이점을 명명하기 위해 이런 종류의 컨트롤러를 'Presenter'라고 부르기로 하며 전체 모델을 Model-View-Presenter 또는 MVP라고 정했습니다.
MVP 내 프레젠터의 역할은 사용자가 시작한 이벤트와 제스처를 해석하고 이를 의도한 방식으로 모델을 조작하기 위해 적절한 명령에 매핑하는 비즈니스 로직을 제공하는 것입니다. 

즉, MVP 기반 프로그램을 만들 때, 개발자는 데이터 관리, 사용자 인터페이스 2가지 분리된 관심사에 대해 각각 3가지 질문을 고려하면 됩니다. 

좀 더 나아가 Data Mgmt 부분을 서버가 담당하고 UI 부분을 Client가 담당해 MVP구조를 클라이언트-서버 구조로 확장 시키는 내용이 추가로 있습니다.

- MVP Programming Model Classes

IModel, IView, ISelection, ICmd, IInteractor 및 IPresenter와 같은 각 MVP 개념에 대한 기본 클래스가 있습니다. 개발자는 이러한 기본 클래스를 상속받아 적절히 재정의하며 원하는 기능을 구현함으로써 이 추상화의 특정버전을 만들 수 있습니다.

  • 가장 간단한 형태로 IMyModel은 myData를 개인 데이터 멤버로 정의하고IModel의 getData, setData 메소드를 재정의하여 myData를 읽고 씁니다.
  • IMyView는 IView의 drawContents 메소드를 재정의하여 화면에 myData 표시를 구현합니다. MVC가 그렇듯 Observer Synchronization 접근 방식을 통해 업데이트될 수 있습니다.
  • MySelection은 myData의 간단한 선택을 정의하고 하이라이트 선택을 제공해 선택 항목이 화면에 나타나게 합니다.
  • ICmd의 별도 하위 클래스는 원하는 명령(잘라내기, 복사 등)에 대해 생성됩니다. 각 명령에 doCmd, undoCmd, redoCmd에 대한 메서드가 있어 시스템이 여러 수준의 명령 실행, 취소, 재실행을 제공할 수 있습니다.
  • 대부분의 일반 애플리케이션은 자체 Interactor를 만들 필요가 없습니다. 미리 정의된 IMenuInteractor등과 같은 일반적인 사용자 인터페이스 하위 클래스를 인스턴스화 해 현재 선택 항목에서 해당 명령이 호출되도록 요청합니다.
  • 마지막으로 개발자는 최상위 애플리케이션 프레임워크를 나타내는 IPresenter에서 특정 모델, 뷰, Selection, Cmd, Interactor를 만들고 이를 모두 함께 연결하여 작동하는 응용 프로그램을 만듭니다

 

 

- Dolphin Smalltalk 의 차이점

Dolphin Smalltalk이 소개한 MVP에 대한 설명도 비슷하지만 Command, Selection을 통해 모델에 작용하는 구조가 없고, 위 Potel이 작성한 것에 비해 프레젠터가 직접 뷰를 조작하는 것에 대한 명시적인 이야기가 있었습니다.

Dolphin Smalltalk의  MVP는 Taligent처럼 계층 분리를 세세히 하지 않고 그저 MVC 패턴에서 사용자 입력을 View가 처리한다는 점이 차이점을 가집니다.

MVC(1972) 이후 1990년대에 와서 입력 처리가 간단해지며 Controller의 존재 의미가 약해지고 UI가 복잡해지며 입력을 View에서 처리하고 Controller가 Presenter라는 형태로 발전했습니다.


 

 

- Supervising Controller (Bower and McGlashan)

Presenter에 모든 책임을 집중시키지 않고 간단하거나 뷰에서 처리하기 유리한 로직은 뷰에서 처리하고 Presenter는 더 복잡한 로직을 처리하는 방식입니다. 기본적으로 MVP 아키텍처를 Dolphin 형태로 반영합니다.

이 방법은 입력 응답과 부분적 뷰/모델 동기화라는 2가지 주요 책임이 있습니다.

입력 응답을 위해 컨트롤러는 Presenter 스타일로 작동합니다. 입력은 처음에 화면 위젯이 받으며, 이를 프레젠터에게  전달해 프레젠터는 복잡한 로직을 처리합니다.

뷰 / 모델 동기화로 뷰에서 처리하기 유리한 부분을 따로 처리합니다. *데이터 바인딩과 같은 방식으로 구현하며, 이때 데이터 바인딩은 컨트롤러보다 더 복잡한 상호작용을 처리하지 않습니다.

*데이터 바인딩 : 데이터 원본을 결합시켜 동기화 하는 기법으로 적절한 Event를 통해 단방향으로 동기화 하는 단방향 데이터 바인딩(즉시 업데이트 X 지연 업데이트 가능)과 프레임워크를 토해 데이터 변경에 따라 즉각 업데이트 하는 양방향 데이터 바인딩이 있습니다. 일반적으로 UI와 Data를 바인딩합니다. (C# ObservableCollection 양방향 데이터 바인딩?)

한 곳에서 모든 처리를 해 너무 무거워졌거나 테스트 용이성을 위한 2가지 경우에 사용을 고려할 수 있습니다. 그 중에서 Martin Fowler는 테스트 용이성에 이유가 설득력 있다고 생각합니다. 특히 간단한 로직과 복잡한 로직의 경계가 불분명하기 때문에 그 구분이 힘들다면 무거움에 상관 없이 이해하기 어려울 수 있기에 상황에 맞게 생각해야합니다.


 

 

- Passive View (Bower and McGlashan)

Supervising Controller와 유사하지만 Passive View는 모든 뷰 업데이트 로직을 컨트롤러에 배치한다는 차이점이 있습니다. 

이름처럼 View를 매우 가볍게 만드는데, Passive View의 View는 모델을 의존하지 않고 오로지 Presenter만 의존합니다.
Presetner는 View와 Model 사이에서 중재자 역할을 하며 대부분의 로직을 처리합니다. 이 덕분에 뷰에서 문제가 발생할 위험이 거의 없어 컨트롤러에서만 테스트를 집중할 수 있습니다.

이 경우 View를 가볍게 만들고 Presenter에만 의존하다 보니 View와 Model 사이 옵저버 동기화를 제거합니다.


 

 

- UI 테스트

visual한 것들은 테스트 하기 어렵습니다. 기본적으로 UI는 복잡한 사용자 상호작용과 결합되어 있고, 이런 사용자 상호작용은 코드로 시뮬레이션하기 쉽지 않습니다. 또 UI는 플랫폼에 종속적이어 실행 환경과 테스트 환경이 동일하지 않다면 제대로 테스트하기 어렵습니다.

그렇기에 Supervising Controller, Passive View 모두 Presenter에 부담을 전가해 View를 가볍게 만들어 Presetner를 테스트하도록 합니다. 둘의 차이점은 Presenter에 책임이 어느정도인지 차이일 뿐입니다.


 

 

- 정리

MVC 패턴과 MVP에 주요 차이점은 입력을 처리하는 책임에 주체입니다.
MVC 초창기(1970)에는 컨트롤러에 입력 처리가 매우 어렵기에 이를 전담하는 Controller가 필요했었지만,
MVP 초창기(1990)에 와서 더 복잡한 UI와 입력들로 각각 개별 View가 입력을 받아서 Presenter에 전달해 Presenter가 입력을 해석하게 되었습니다.

MVC에서 Controller는 복잡한 입력을 처리하는것이 주 역할이지 Model로 요청을 전달하는 일은 과정에서 생긴 부수적인 역할입니다.
반대로 MVP에서 Presenter는 View에서의 입력을 해석해 Model로 요청하는 것이 존재이유입니다.

MVC에서 MVP로 넘어가게된 이유는 UI 구현 기술이 점점 발달하며 위젯, 컴포넌트와 같은 개념이 등장했고 입력 처리가 간단해지면서 Controller에 역할은 점점 줄어들었지만 UI는 점점 복잡하고 화려해졌기 때문입니다.
Controller의 역할이 줄어들며 입력을 View에서 처리하고 Controller는 Model에 전달하는 역할로 바뀌며 MVP가 등장했지만 Taligent의 초창기 MVP는 관심사와 책임을 너무 세세히 분리해 사람들이 공감할 수 없는 수준으로 계층을 분리했습니다. 
점점 복잡하고 화려해진 UI는 테스트하기 어렵다는 이유 때문에 View에 표현 로직을 Presenter로 전담하는 Supervising Controller, Passive View 등으로 발전했습니다.

테스트에 대한 고민은 Presenation Model, Model-View-ViewModel로 발전됩니다.

 

*참고출처