[Design Pattern] MVP 패턴
MVP 패턴이란?
MVP(Model-View-Presenter)는 소프트웨어 디자인 패턴으로, MVC(Model-View-Controller) 패턴의 변형입니다.
View와 Presenter 사이의 의존성을 줄이고 역할을 더 명확히 하여, 특히 UI가 많은 애플리케이션에서 적합한 패턴입니다.
구성요소
- Model
- 애플리케이션의 데이터와 로직을 담당.
- 데이터를 가져오거나 업데이트하는 역할을 합니다.
- Presenter와만 통신하며, View와 직접적으로 연결되지 않습니다.
- View
- 사용자 인터페이스를 담당하며, Presenter와의 소통을 위한 역할만 수행.
- 사용자가 데이터를 입력하거나 UI를 확인하는 부분입니다.
- 로직은 포함되지 않고, Presenter에서 전달받은 데이터를 기반으로 UI를 업데이트합니다.
- Presenter
- View와 Model을 중재하며, 비즈니스 로직을 처리합니다.
- View에서 사용자 입력을 받고, Model을 통해 데이터를 처리한 뒤 결과를 다시 View에 전달합니다.
- View와 Model 간의 강한 의존성을 제거합니다.
MVP의 동작 흐름
- 사용자가 View를 통해 입력을 제공.
- View는 Presenter에게 입력을 전달.
- Presenter는 Model에 데이터를 요청하거나 수정.
- Model의 데이터를 Presenter가 다시 View에 전달.
- View는 Presenter로부터 받은 데이터를 화면에 표시.
장단점
장점
- 테스트 용이성
- Presenter는 View에 의존하지 않고 인터페이스를 통해 작동하므로, 단위 테스트가 쉽습니다.
- 독립적인 View
- View는 Presenter와만 연결되어 있어, View를 교체하거나 수정할 때 영향을 최소화합니다.
- 역할 분리
- UI(View)와 로직(Presenter)이 분리되어, 유지보수성과 코드 재사용성이 높아집니다.
단점
- 복잡성 증가
- Presenter와 View 간의 연결을 위해 인터페이스를 정의해야 하므로, 코드 구조가 복잡해질 수 있습니다.
- 작은 프로젝트에는 과도
- 간단한 애플리케이션에서는 오히려 불필요하게 코드가 늘어날 수 있습니다.
MVP와 MVC의 차이점
- View와의 의존성
- MVC에서는 View와 Controller 간에 의존성이 있지만, MVP에서는 View가 Presenter와만 통신하며 인터페이스를 통해 연결됩니다.
- 테스트 용이성
- MVP는 View가 인터페이스를 사용하기 때문에 Mocking이 쉬워 테스트하기 용이합니다.
- 데이터 흐름
- MVC는 Controller가 사용자 입력을 받아 Model을 직접 갱신하고, View가 데이터를 구독하는 방식.
- MVP는 Presenter가 모든 흐름(입력, 로직 처리, UI 업데이트)을 제어합니다.
샘플 코드
Model
using System;
public class UserModel
{
private readonly string validUsername = "user";
private readonly string validPassword = "password";
public bool ValidateUser(string username, string password)
{
return username == validUsername && password == validPassword;
}
}
View
using System;
public interface ILoginView
{
string Username { get; }
string Password { get; }
void DisplayMessage(string message);
}
public class LoginView : ILoginView
{
public string Username { get; private set; }
public string Password { get; private set; }
public void GetUserInput()
{
Console.Write("Enter Username: ");
Username = Console.ReadLine();
Console.Write("Enter Password: ");
Password = Console.ReadLine();
}
public void DisplayMessage(string message)
{
Console.WriteLine(message);
}
}
Presenter
public class LoginPresenter
{
private readonly ILoginView _view;
private readonly UserModel _model;
public LoginPresenter(ILoginView view, UserModel model)
{
_view = view;
_model = model;
}
public void HandleLogin()
{
string username = _view.Username;
string password = _view.Password;
if (_model.ValidateUser(username, password))
{
_view.DisplayMessage("Login Successful!");
}
else
{
_view.DisplayMessage("Invalid Username or Password.");
}
}
}