1. 시작하기 전에
public class MainActivity extends AppCompatActivity {
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//뷰 작성
setContentView(R.layout.activity_main);
textView = findViewById(R.id.text_view);
//이벤트 처리후 뷰 업데이트
textView.setOnClickListener(view -> {
textView.setText(clickedTextView());
});
}
private String clickedTextView(){
return "Hello World!";
}
기존에 별다른 생각 없이 코드를 작성 했을때는 위와같은 방법으로 대부분 구현했다.
아주 간단한 예제이지만 뷰, 이벤트 리스너, 데이터 처리 등이 모두 한 액티비티안에 존재한다.
이러한 식으로 구현하면 규모가 커질수록 하나의 액티비티가 복잡하고 비대해져 문제가 생길 수 있고 문제에 대한 유지보수에도 어려움이 있을 수 있다.
또 액티비티 특성상 LifeCycle에 따른 영향도 있을 것이며 데이터도 안전하게 다루지 못한다.
따라서 LifeCycle의 영향, 코드의 복잡, 비대에대한 영향, 앱 사용 환경 등 다양한 이유와 문제점을 바탕으로 좀 더 안전하고 깔끔한 개발을 위해 아키텍처 패턴이 생겨났다
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal|center_vertical">
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="push!" />
</LinearLayout>
2. MVC
- 구조 및 동작
- MVC 패턴에서는 사용자 입력은 컨트롤러(Activity)를 통해 들어오며 컨트롤러는 모델과 상호작용을 통해 View(xml)를 업데이트 한다.
- 이때 뷰는 모델을 참조하게 된다.
특징
Controller(Activity)
- 앱을 묶어주는 접착제 역할(Activity / fragment)
- 사용자에게 입력을 받아 해당하는 모델을 선택하여 처리한다.
- 모델의 데이터 변화에 따라 뷰를 선택한다.
Veiw(XML)
- 사용자에게 제공되는 UI
- UI, 앱과의 상호작용에서 컨트롤러와의 통신
- 사용자가 어떤 액션을 하든 무엇을 해야할지 모름
Model
- 데이터 + 상태 + 비지니스 로직
- View나 컨트롤러에 묶이지 않아 재사용 가능
장단점
장점
- Model과 View를 분리
- Model의 비종속성으로 재사용 가능
- 구현하기 가장 쉬움
단점
- 컨트롤러가 View에 결합되며, VIew의 확장이 될 수 있음
- View와 Model 사이의 업데이트를 위해 직/간접적으로 참조 이로 인해 서로간의 의존성을 완벽하게는 없앨 수 없음
- 규모가 커질수록 컨트롤러에 많은 코드가 쌓여 비대화 문제 발생
- 예제
public class MainActivity extends AppCompatActivity {
private Model model;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//View 작성
setContentView(R.layout.activity_main);
textView = findViewById(R.id.text_view);
//Controller 작성
model = new Model();
textView.setOnClickListener(view -> {
textView.setText(model.clikedButton());//Model 부분
});
}
}
public class Model {
String clikedButton(){
return "Hello World! - MVC";
}
}
예제의 MainActivity.java 를 보면 View와 클릭이벤트 즉 Model의 처리가 함께 있는것을 확인 할 수 있다. 이러한 직/간접적인 참조를 개선하기 위해 MVP와 MVVM 아키텍처 패턴이 생겨났다.
3. MVP
- 구조 및 동작
- Model과 View는 MVC의 개념과 동일하다
- Model과 View를 분리 시키기 위해 사이에 Presenter라는 개념을 추가시킨다
- 사용자 입력은 이제 View를 통해 들어온다.
- View는 이러한 이벤트를 Presenter로 전달하고 Presenter는 Model과의 상호작용을 통해 View에게 업데이트 할 내용을 전달한다.
- 내용을 전달받은 View가 최종적으로 업데이트 된다
- 이로 인해 Presenter와 View는 1:1 관계를 유지한다
특징
Presenter
- Model과 View의 상호작용 관리
- 컨트롤러와 본질적으로는 동일 하지만 View에 연결되지 않는 단순 interface이다.
- VIew에게 표시할 내용만 전달
- Model과 View의 상호작용 관리
View
- 사용자에게 제공되는 UI
- Activity / fragment가 View의 일부로 간주된다.
- 사용자의 입력을 받고 이벤트를 Presenter로 전달한다
Model
- MVC와 동일
장단점
장점
- Model과 View의 의존성이 존재하지 않는다
- Model은 Presenter의 요청만을 수행한다
단점
- 규모가 커짐에 따라 Presenter도 추가 비지니스 로직이 모여 비대화 된다
- MVC에 비해 필요한 클래스 수가 증가한다
- View와 Presenter의 1:1 관계로 인한 의존성 증가
- 예제
public class Model {
String clikedButton(){
return "Hello World! - MVP";
}
}
public interface Presenter {
void confirm();
interface View{
void setText(String text);
}
}
public class PresenterImpl implements Presenter{
private Presenter.View view;
private Model model;
PresenterImpl(View view){
this.view = view;
this.model = new Model();
}
// Model에 데이터 요청 후 View에 업데이트 내용 전달
@Override
public void confirm(){
if(view != null){
view.setText(model.clikedButton());
}
}
}
public class MainActivity extends AppCompatActivity implements Presenter.View {
private Presenter presenter;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
presenter = new PresenterImpl(MainActivity.this);
textView = findViewById(R.id.text_view);
textView.setOnClickListener(view -> { presenter.confirm();}); //Presenter로 이벤트 전달
}
// Presenter로 부터 전달받은 내용으로 View 업데이트
@Override
public void setText(String text){
textView.setText(text);
}
}
MVP는 Presenter가 Model과 View 사이에서 관리를 해주기 때문에 Model과 View 사이의 의존성이 없다.
그러나 규모가 커지면 Presenter와 View 의 1:1 관계로 인해 의존성이 강해지는 문제점이 있다.
이러한 문제를 해결하기위해 MVVM 아키텍처 패턴이 생겨났다
4. MVVM
- 구조 및 동작
- Model과 View는 MVC의 개념과 동일하다
- MVP와 마찬가지로 View와 Model을 분리시키기 위해 ViewModel이라는 개념이 들어온다
- View는 사용자 입력에 따른 자신이 이용할 ViewModel을 선택해 바인딩하여 업데이트를 받는다
- ViewModel과 Model이 상호작용을 하여 Model이 변경되면 ViewModel을 이용하는 View가 자동으로 업데이터 된다.
- 이로인해 View와 Model 사이의 의존성이 없고, MVP 처럼 View 와 ViewModel이 1:1 관계가 아닌 독립적이기 때문에 이 둘 사이의 의존성이 없다
장단점
장점
- View에 대한 의존성이 전혀 없으므로 유닛 테스트에 용이
- 중복되는 코드를 모듈화 할 수 있음
단점
- ViewModel의 설계가 어렵다
- View에대한 처리가 복잡할수록 ViewModel이 거대해진다
- 상대적으로 View는 아무 역할도 하지 않음
- ViewModel이 또다른 형태의 액티비티 클래스 구현으로 변질될 우려가 있다
특징
ViewModel
- View를 나타내주기 위한 Model + View의 로직 담당
- View와 독립적
- UI 관련 데이터 보관 및 관리
- Model이 변경되면 해당 ViewModel을 사용하는 View가 자동으로 업데이트
View
- 사용자에게 제공되는 UI
- 사용자의 입력을 받고 이벤트를 자신이 사용할 ViewModel로 전달
Model
- MVC와 동일하다
예제
public class Model {
String clikedButton(){
return "Hello World! - MVVM";
}
}
public class ViewModel {
private Activity activity;
private Model model;
private TextView textView;
ViewModel(Activity activity){
this.activity = activity;
this.model = new Model();
initView();
}
private void initView(){
//View의 표현과 Model과의 상호작용
textView = activity.findViewById(R.id.text_view);
textView.setOnClickListener(view -> {
textView.setText(model.clikedButton());
});
}
}
public class MainActivity extends AppCompatActivity {
private ViewModel viewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//ViewModel에 위임
viewModel = new ViewModel(MainActivity.this);
}
}
ViewModel의 initView() 부분을 보면 기존 액티비티에서 하던 일을 ViewModel이 하는것을 볼 수 있다.
이것이 MVVM 패턴이 액티비티의 LifeCycle의 영향을 받지 않고 ViewModel 인스턴스가 유지되면서 데이터를 안전히 다룰 수 있는 이유다.
그러나 앞서말했듯이 View가 할 일을 ViewModel이 대신 하기때문에 ViewModel에 로직들이 모이고 또다른 View 클래스를 생성한 꼴이 될 수 있으므로 유의하며 구현해야 한다.
reference
https://stonybean.blogspot.com/2019/03/blog-post.html
https://kkangsnote.tistory.com/9
https://brunch.co.kr/@oemilk/113
'Study > Android' 카테고리의 다른 글
Could not load wrapper properties from 오류 - Android (0) | 2021.05.14 |
---|