이번에는 Presenter와 View를 나누는 방법에 대해서 정리해보겠다.

Presenter의 정의는?

  • View : Presenter에서 전달받은 View의 이벤트이다.
  • Presenter : View에서 전달된 이벤트에 대한 처리를 한다.(View와 무관한 처리만 한다.)

Presenter를 구분하는 방법들

  1. View에 대한 interface만 정의하는 방법
  • interface View : View에 대한 interface만 정의
  • Presenter : interface 정의 없이 함수를 생성하여 사용
  • View : interface View를 상속받아서 정의
  1. Google architecture를 따른다.
  • Contract : View와 Presenter에 대한 interface을 작성
  • Presenter : Contract.Presenter을 상속받아서 구현
  • View : Contract.View을 상속받아서 구현
  1. PresenterImpl을 구현
  • Presenter : Presenter와 View에 대한 interface을 구현
  • PresenterImpl : Presenter을 상속받아서 구현
  • View : Presenter.View을 상속받아서 구현

위와 같이 구현하는 방법은 크게 3가지 정도로 나뉠 수 있다. 정답은 없고 편한 방법과 다른 사람과 공유했을 때의 장/단점을 따져서 작성하면 좋겠다.

interface 정의시의 장점은 처음 보는 사람이 파익이 쉽다이고, 단점은 여기나 interface 정의가 너무 많다는 것이 될 수 있습니다. 결국, View와 Presenter 간의 통신을 위한 리스너 역할의 interface view에 대한 정의는 처리가 되어야 한다.

Googl Architecture을 따르면

구글에서 정의하는 Presenter의 생성 방법은 다음과 같다.

  • Presenter의 생성은 View가 아닌 실제 View가 만들어지는 시점의 Activity/Fragment/View 등에서 생성을 하고 해당 Presenter에 setView를 실행한다.
  • setView가 호출되는 시점에 자기 자신(this)을 setPresenter 함수를 통해서 실제 Presenter가 사용되어야 할 View에 전달한다.
  • View에서는 setPresenter을 통해서 전달받은 Presenter을 가지고 이후 loadItem, OnClickLstener 등의 처리를 한다.

여기서 의문점

Activity만 있는 경우는??

  • Activity만 있는 경우인데 별도의 View를 생성해야 하는가?
  • 그냥 자기 자신이 받아도 되는가?

의문에 대한 대답

  • 구글이 제안하는 방법대로라면 - 별도의 View가 있다고 생각하는게 좋겠죠? 코드의 통일성을 위해서 - 자기 자신이 받는 것은 없다고 보면 된다.

정리하자면

  • 결국 자기 자신이 new Presenter을 처리할 수 있어야 한다.
    • 그럼 setPresenter라는 메소드가 필요하지 않게 된다.
  • Activitiy/Fragment/View 등에서 필요한 경우 Presenter을 생성하고, 자기 자신이 사용할 수 있어야 한다.

그럼 어떻게?

위와 같은 문제점에 대한 제안된 방법은 아래와 같다.

  • Activity/Fragment/View에서 필요한 Presenter을 직접 생성
  • setView를 전달한다.
  • loadItem을 직접 호출
  • View을 통해서 처리 결과에 다른 View을 갱신한다.

Contract 구현하기

이번에는 구글의 Contract 정의를 따를 예정이므로 Contract를 구현한다. Contract를 사용하는 이유는 간단하다. View와 Presenter을 각각 정의하기 위함이며, 이해를 돕기 위한 이유도 있다.

하나의 interface에 View/Presenter을 정의하고, 이를 각각의 View와 Presenter에서 정의하는 방식이다.

먼저 View와 Presenter을 각각 다음과 같이 구현할 수 있다.

1
2
3
4
5
6
7
8
9
10
public interface SampleContract{
interface View{
// View method
}

interface Presenter{
// Presenter method
void setView(View view);
}
}

Presenter 상속 정의

Presenter는 다음과 같은 방식으로 구현한다.

SampleContract.Presenter을 상속받아서 구현하며, SampleContract.View을 가지게 된다.

1
2
3
4
5
6
7
class SamplePresenter : SampleContract.Presenter{
private var view : SampleContract.View? = null

override fun setView(view : SampleContract.View){
this.view = view
}
}

View 상속 정의

SampleContract.View를 상속받으면 다음과 같이 정의해주면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class SampleActivity extends AppCompatActivity implements SampleContract.View {

private SampleContract.Presenter presenter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

presenter = new SamplePresenter();
presenter.setView(this);

presenter.loadItem();
}

@Override
public void updateView(List<Items> items) {
// UI 갱신
}
}

참고