brunch

You can make anything
by writing

C.S.Lewis

by 서준수 Apr 27. 2022

안드로이드 MVP

아키텍처 패턴

MVC에 이어서 살펴볼 아키텍처 패턴은 MVP이다. 안드로이드에서 MVP는 MVC와 유사한 형태를 갖는다. 구조적으로는 비슷하게 보일 수 있으나 각각의 역할에 변화가 있고 그로 인해 큰 차이점이 생긴다.


MVP

MVP는 Model, View, Presenter의 약자이다. 안드로이드에서 각각에 해당하는 것은 무엇이며 각각의 역할은 무엇인지 알아보자.


Model

MVC와 동일한 개념이며 의존성이 없었기 때문에 이번에 다룰 MVP 예제에서 그대로 사용 가능하다. (앱에서 사용하는 데이터, 상태, 비즈니스 로직을 포함한다. 데이터는 사용자의 이름이나 상품의 가격 등과 같은 말 그대로 데이터를 의미한다. 상태는 UI 상태이다. isEnabled와 같은 플래그로 UI의 상태를 나타낼 수도 있고 데이터의 값이 변경되어 UI가 갱신되어야 한다면 그 또한 상태 변경으로 볼 수 있다. 비즈니스 로직은 앱에 필요한 동작을 수행하기 위해서 데이터를 처리하기 위한 알고리즘이다.)


View

MVC에서와 마찬가지로 UI 요소를 담당한다. 다만 이제 Activity와 Fragment도 View로 분류한다. UI 갱신과 같은 작업을 View에서 직접 처리해야 하기 때문이다. 왜 그렇냐면 다음의 Presenter의 역할을 보면 이해가 될 텐데 Presenter가 UI 갱신을 View에 요청하기 때문이다MVC를 생각해보면 Controller 역할을 했던 Activity 또는 Fragment에서 UI 갱신을 한다. 그 역할을 하던 것들이 View로 분류되었으니 View에서 UI 갱신을 하게 된 것으로 생각하면 된다. Controller가 했던 역할이 하나 더 있는데 바로 Model과 상호작용이다. 그러나 이제 그 역할을 하던 Activity와 Fragment가 View에 속했으니 Model과 상호작용은 직접 하지 않는다. 대신 그 역할은 Controller처럼 View와 Model 사이의 가교 역할을 하는 Presenter에게 맡긴다. 따라서 View와 Presenter 간에 의존성이 생긴다. 이때 Presernter와 Activity가 직접 연결되지 않도록 View interface를 만들고 Activity가 implements 하여 해당 interface로 연결하면 가상의 View interface로 가상의 객체를 만들 수 있어 Presenter 로직 테스트에 용이하다.


Presenter

MVC의 Controller의 역할과 유사하다. Model과 상호작용하고 View에 UI 갱신을 요청한다. 다만 직접 UI를 갱신하는 것이 아니라 어떤 걸 보여줘야 하는지에 대한 정보만 View에 전달한다. 실제 UI 갱신은 View에 맡기는 것이다. 이 말인즉슨 Presenter는 Controller와 다르게 View와 직접적으로 연결되는 것이 아니라 가교 역할만을 한다는 것이다. View와의 의존성은 여전히 남아있다. 당연히 Model과의 의존성도 있다.

위 설명들을 바탕으로 구조를 표현하면 위와 같다. 그림을 보면 View와 Model은 서로 분리되어 있는 것을 알 수 있다. 또한 Model은 종속되는 곳이 없기 때문에 테스트하기 쉽고 재사용하기 용이하다. 그러나 Presenter 입장에서는 View와 Model에 대한 의존성이 생긴다. View 또한 Presenter와 의존성이 생긴다. Presenter와 View는 서로 의존성을 갖는 것이다. MVP의 문제점도 결국 Controller와 비슷한 역할을 하는 Presenter에 많은 코드가 쌓이게 될 가능성이 높다는 것이다.


예제

MVC에서 다룬 예제와 동일한 동작을 하는 앱을 MVP를 적용하여 구현한다.



[Model]

MVC 예제와 완전히 동일하다. 파일을 그대로 복사해서 사용해도 된다. MVP에서도 Model은 의존성 없이 독립적이기에 가능하다.


[Presenter]

Presenter는 MVC의 Controller와 유사한 역할을 한다. Presenter에서 해야 할 동작은 다음과 같다.

1. 메뉴(아메리카노) 수량 증감 요청 (to Model)

2. UI 갱신을 위한 수량 변경 정보 전달 (to View)

3. 수량 증감에 따른 합계 가격 증감 요청 (to Model)

4. UI 갱신을 위한 수량 변경에 따른 합계 가격 정보 전달 (to View)


Controller와 차이점은 UI를 직접 갱신하는 것이 아니라 View에 반영될 정보를 전달만 한다. 이때 View에 대한 의존성이 생기는데 View 자체에 대한 의존 대신 View interface를 의존성 주입받아서 사용하도록 하여 유연하게 설계한다. 반대로 View가 입력 이벤트를 전달하기 위해 Presenter에 의존성이 생기는데 이때 사용할 interface도 만든다. View가 Presenter를 호출할 때 어떤 동작을 하려는 것인지 파악하기 쉽다.

2 : UI 갱신을 위한 아메리카노 수량 증가 정보 전달 (추상화)

3 : UI 갱신을 위한 아메리카노 수량 감소 정보 전달 (추상화)


2 : View interface를 전달받는다. (의존성 주입)

6 : 아메리카노 수량 감소 버튼 입력이 들어왔을 때 View가 호출할 함수

12 : 아메리카노 수량 증가 버튼 입력이 들어왔을 때 View가 호출할 함수

18 : 아메리카노 수량 감소 시 합계 가격 데이터 변경 및 UI 반영 요청을 위한 함수 

23 : 아메리카노 수량 증가 시 합계 가격 데이터 변경 및 UI 반영 요청을 위한 함수


[View]

Presenter가 UI 갱신 요청을 위해 View를 호출할 때 필요한 동작을 OrderView interface를 만들어 정의한다. 갱신할 UI는 아메리카노 수량과 합계 가격 두 가지이다. Model과는 직접적으로 상호작용하지 않고 Presenter가 가교 역할을 한다.

2 : 아메리카노 수량 UI 반영 (추상화)

3 : 합계 가격 UI 반영 (추상화)


16 : 아메리카노 수량 감소 버튼 이벤트가 발생하면 Presenter에 이벤트 발생을 알린다.

20 : 아메리카노 수량 증가 버튼 이벤트가 발생하면 Presenter에 이벤트 발생을 알린다.

25 : 아메리카노 수량 UI 반영 구현

29 : 합계 가격 UI 반영 구현


위 예제에서는 두 개의 버튼에 대한 입력과 두 개의 텍스트뷰에 대한 UI 변경 정도이다. 하지만 CafeLatte 메뉴 하나만 추가되어도 두 개의 버튼과 한 개의 텍스트뷰가 추가된다. 이런 식으로 Presenter가 할 일이 계속 늘어나면 결국 비대한 코드 덩어리가 될 가능성이 있다. 반면에 OrderView interface를 구현하였기 때문에 가상의 View나 다른 View를 통해서 Presenter 로직 테스트를 하기 쉽다는 장점이 있다.

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari