1. MVP 아키텍처 개요
MVP(Model-View-Presenter)는 애플리케이션을 세 가지 주요 구성 요소로 분리하는 아키텍처 패턴입니다.
- Model: 데이터 처리 계층. 데이터 저장 및 검색을 담당
- View: UI 표시 계층. 사용자 상호작용을 처리
- Presenter: 비즈니스 로직 계층. View와 Model을 연결
1.1 주요 장점
- 역할 분리
- View: UI 표시에만 집중
- Model: 데이터 조작에만 집중
- Presenter: 비즈니스 로직 처리
- 결합도 감소
- 인터페이스 기반 통신
- 각 계층 독립 개발 가능
- 단위 테스트 용이
- 코드 유지보수성 향상
- 로직 구조화
- 모듈 간 영향 최소화
- 재사용 가능성 증대
1.2 아키텍처 구조도
View <--> Presenter <--> Model ↑ ↑ ↑ Interface Interface Interface
2. 노트패드 앱 분석 및 리팩터링
기존 코드: https://github.com/yape29/android_notePad/tree/master
리팩터링 코드: https://github.com/yape29/android_notePad/tree/20241209-MVP설계모델재구성응용
2.1 기존 구조 분석
2.1.1 NotesList.java 분석
View 부분:
- 노트 목록 레이아웃(notelist_main.xml)
- ListView로 노트 표시
- FloatingActionButton으로 노트 추가
- 검색 입력창 및 버튼
- 분류 표시 버튼
- 즐겨찾기 기능 버튼
Presenter 로직(추출 필요):
- 노트 목록 데이터 로드
- 검색 처리
- 분류 표시
- 즐겨찾기 관리
- 노트 삭제
- 새 노트 생성
2.2 컨트랙트 인터페이스 정의
public interface NotesContract {
interface NotesView {
void showNotes(Cursor cursor);
void showError(String message);
void openNoteEditor(Uri uri);
void finishView();
void refreshView();
void updateListView(Cursor cursor);
void showDeleteButton(boolean show);
}
interface NotesPresenter {
void loadNotes();
void loadNotesInClassify(String classifyName);
void loadClassifies();
void deleteNote(Uri noteUri);
void createNote();
void onDestroy();
}
interface NoteEditorView {
void showNote(Cursor cursor);
void showError(String message);
void finishView();
void updateTitle(String title);
void updateText(String text);
void showClassifyDialog(Cursor classifyCursor, String currentClassify);
}
interface NoteEditorPresenter {
void loadNote(Uri uri);
void saveNote(String text, String title);
void deleteNote();
void loadClassifies();
void updateNoteClassify(String classify);
void createNewClassify(String classifyName);
void onDestroy();
}
}
2.3 Presenter 구현
NotesPresenter 구현
public class NotesPresenter implements NotesContract.NotesPresenter {
private NotesContract.NotesView viewRef;
private Context contextInstance;
public NotesPresenter(NotesContract.NotesView view, Context context) {
this.viewRef = view;
this.contextInstance = context;
}
@Override
public void loadNotes() {
try {
String[] projection = {
NotePad.Notes._ID,
NotePad.Notes.COLUMN_NAME_TITLE,
NotePad.Notes.COLUMN_NAME_MODIFICATION_DATE,
NotePad.Notes.COLUMN_NAME_STAR
};
Cursor dataCursor = contextInstance.getContentResolver().query(
NotePad.Notes.CONTENT_URI,
projection,
null,
null,
NotePad.Notes.DEFAULT_SORT_ORDER
);
viewRef.updateListView(dataCursor);
} catch (Exception e) {
viewRef.showError("데이터 로드 실패");
}
}
// 나머지 메서드 구현...
}
2.4 Activity 수정
NotesList.java 수정
public class NotesList extends ListActivity implements NotesContract.NotesView {
private NotesContract.NotesPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
presenter = new NotesPresenter(this, this);
setContentView(R.layout.notelist_main);
FloatingActionButton addBtn = findViewById(R.id.add_note);
addBtn.setOnClickListener(v -> presenter.createNote());
presenter.loadNotes();
}
@Override
public void showNotes(Cursor cursor) {
// 노트 목록 표시 구현...
}
// 다른 인터페이스 메서드 구현...
}
3. 리팩터링 효과 분석
3.1 코드 구조 비교
리팩터링 전:
- NotesList.java (UI + 로직) - View: 리스트 표시, 버튼 배치 - Presenter: 데이터 로드, 이벤트 처리 - NoteEditor.java (UI + 로직) - View: 편집 인터페이스, 버튼 배치 - Presenter: 노트 처리, 분류 관리 - NotePadProvider.java (데이터 처리)
리팩터링 후:
- contract/ - NotesContract.java (인터페이스 정의) - presenter/ - NotesPresenter.java (목록 로직) - NoteEditorPresenter.java (편집 로직) - view/ - NotesList.java (UI 전용) - NoteEditor.java (UI 전용) - provider/ - NotePadProvider.java (데이터 처리)
3.2 장점
- 역할 명확화
- Activity는 UI 작업만 담당
- Presenter는 비즈니스 로직 처리
- Provider는 데이터 저장 집중
- 코드 분리
- 인터페이스 기반 통신
- 모듈 간 독립성
- 테스트 용이성
- 유지보수성 향상
- 구조 명확
- 변경 시 영향 최소화
- 재사용 가능성 증가
4. 결론
MVP 패턴을 활용한 노트패드 앱 리팩터링을 통해:
- 기존 코드의 View와 Presenter 역할 분석
- 명확한 계약 인터페이스 정의
- 코드 분리 및 역할 명확화
- 유지보수성과 테스트 가능성 향상
MVP 패턴은 코드량 증가를 동반하지만, 구조적 이점이 크며 실제 프로젝트에서는 프로젝트 규모와 요구사항에 따라 적절한 아키텍처 선택이 중요합니다.