JAVA

[ JAVA ] MVP 패턴 + 코드 예시

dongx._.2 2023. 5. 17. 02:32

 

 

 

MVP 패턴 구조

 

  • Model : 데이터를 처리하는 부분
  • View : 사용자에게 보여지는 UI 부분
  • Presenter : View의 요청을 받아 Model에게 전달하는 부분 (Model이 처리해준 결과를 받아서 View로 반환)

기타 클래스

 

Entity

  • Entity 클래스DB 테이블과 직접적으로 매핑 되는 클래스를 뜻함
  • 쉽게 생각하면 DB 테이블(또는 Json으로 저장된 파일)과 형태가 일치

Playlist.json

  • 플레이리스트 데이터가 아래와 같은 Json 형태로 저장되어 있는 경우
{
    "id": "P0000001",
    "title": "플레이리스트 제목",
    "author": "작성자",
    "inform": "설명",
    "likes": 999,
    "downloads": 1023,
    "createTime": "2023-05-17",
    "image": "image url"
}

Playlist.java

  • 플레이리스트 Entity 클래스는 아래와 같이 만들어지면 됨
public class Playlist {
    public String id;     
    public String title;
    public String author; 
    public String inform;
    public int likes;
    public int downloads;
    public Date createTime;
    public String image;
}

 

Dto

  • DtoEntity 클래스 중 필요한 데이터만 뽑은 클래스라고 생각하면 됨
  • JPA를 사용하는 경우 Entity는 DB 테이블과 직접적으로 매핑 되므로 Entity를 함부로 건들여선 안됨
  • 이를 위해서, 데이터를 처리할 때는 Dto를 쓰고, 최종적으로 DB나 파일에 반영할 때 Entity로 변환

Playlist.java

  • 플레이리스트 생성에 필요한 데이터만 뽑은 Dto
  • 생성할 때 필요 없는 Entity의 속성(id, likes, downloads)들은 제외 함
public class PlaylistCreateDto {
    public String title;
    public String author;   // FK >- User.Id
    public String inform;
    public String image;
    public Date createTime;
}

 


View

  • 화면 디자인, 요소 배치 등을 처리
  • 이벤트 처리

Presenter

  • ❗Presenter는 View를 갖고 있으면 안됨❗
  • PresenterService만 인스턴스로 가지며, View의 요청을 Service에게 위임하는 역할을 함
public class PlaylistPresenter{
    // Presenter는 View를 가지지 않음
    // 로직 처리에 필요한 Service들을 가짐
    private PlaylistService playlistService;
    private PlayBsideTrackService playBsideTrackService;

    private PlaylistController() { 
        this.playlistService = new PlaylistService(); 
        this.playBsideTrackService = new PlayBsideTrackService();
    }
    
    /* 생략 */
    
    /**
    * 플레이리스트를 수정하는 메소드
    */
    public Playlist updatePlaylist(PlaylistUpdateDto updateDto){     
        // Service에게 Update 요청
        Playlist result = playlistService.updatePlaylist(updateDto);
        
        if(result == null) {
            System.err.println("업데이트 실패");
            return null;
        }
        
        return result;
    }
}

 


Model

Model은 Service와 Repository로 나뉨

Service

  • 비즈니스 로직을 처리
  • 필요한 데이터가 있거나 파일 입출력 / DB에 접근 해야하는 경우는 Repository에게 요청
  • Service는 절대 직접적으로 저장소(로컬, DB)에 접근하지 않음
    // 플레이리스트 수정
    public Playlist updatePlaylist(PlaylistUpdateDto dto){
        // 업데이트할 플레이리스트를 가져옴
        Playlist target = playlistRepository.findById(dto.getId());
        
        if(target == null) return null;
        
        // 변경 부분 반영
        target.patch(dto);
        
        // 업데이트 결과 값 받아옴
        Playlist result = playlistRepository.update(target);
        
        return result;
    }
  • 플레이리스트DB에서 가져오는 부분이나 수정하는 부분을 모두 Repository에게 요청하는 것을 볼 수 있음

회원 가입 Service 예시 (Service는 이부분을 참고)

  • Service 부분은 회원 가입 로직이 좀 더 직관적일 것 같아서 추가
더보기
    // 회원가입 method
    public UserDto SignUp(UserSignUpDto dto) {
    	// id로 사용자 찾아오기
        User target = userRepository.findById(dto.getId());

        // id로 조회한 결과(target)가 존재하면
        // 이미 가입된 아이디라는 뜻
        if (target != null) return null;
            
        // id로 조회간 결과(target)이 없으면 새로운 회원이므로            
        // Repository에게 User 저장 요청
        User user = new User(dto.getId(), dto.getNewPw());
        userRepository.save(user);
        
        // 회원가입 결과를 조회하여 리턴 (회원가입 실패 시 null)
        User result = userRepository.findById(user.getId());
        
        return result == null ? null : UserDto.createDto(result);
    }

Repository

  • 파일 입출력 / DB 접근을 담당
  • 오로지 파일 입출력 / DB 접근만을 담당해야 함
  • Repository는 오직 Entity만 이용함
  • Dto는 자주 변할 수 있으므로 Repository에서 사용하면 안됨
  • 반환 값은 무조건 Entity를 반환 함 (Dto, JSONObject 등 x)
    public Playlist save(/* PlayListDto */) {
    	// 플레이리스트 저장하는 코드
    }
    
    public Playlist deleteById(String id) {
    	// id로 플레이리스트를 삭제하는 코드
    }
    
    public Playlist update(PlaylistUpdateDto dto) {
    	// 플레이리스트를 수정하는 코드
    }

    @Override // 게시글로 등록된 플레이리스트 조회
    public ArrayList<Playlist> findAll() {
        String sql = "SELECT * FROM playlist WHERE id IN (SELECT * FROM playlist_article);";
        this.rs = this.executeQuery(sql);
        
        ArrayList<Playlist> result = resultSetToEntityList(rs);
        db.close();
        
        return result;
    }
    
    // 해당 유저의 플레이리스트만 가져오는 메소드
    public ArrayList<Playlist> findAllByUserId(String userId){
        String sql = "SELECT * FROM playlist WHERE author = \"" + userId + "\";";
        this.rs = this.executeQuery(sql);
        
        ArrayList<Playlist> result = resultSetToEntityList(rs);
        db.close();
        
        return result;
    }
  • Repository에는 위와 같이 CRUD(삽입, 조회, 수정, 삭제)기능만 담당
  • 로직은 전혀 없이 파일 입출력(또는 DB)만 담당하고 있는 것을 볼 수 있음

 

참고 코드

  • MVP가 적용 되었지만 Controller로 작성되어 있음 (Presenter라고 생각하고 보면 됨)

 

 

GitHub - DeuWePLi/WePLi

Contribute to DeuWePLi/WePLi development by creating an account on GitHub.

github.com