본문 바로가기
공부 기록

[JAVA] Builder Pattern ( 빌더 패턴 )_사용 예제 ( Lombok + 일반)

by 타태 2021. 9. 26.

 

 

2021.08.01 - [실전 공부] - 모나코 에디터(온라인 코드 에디터) 스프링 부트 프로젝트에서 사용하기 (타임리프 사용 + 파일 읽어서 뿌려주기)

 

모나코 에디터(온라인 코드 에디터) 스프링 부트 프로젝트에서 사용하기 (타임리프 사용 + 파일

2021.08.01 - [인턴업무] - [JAVA] equals 메서드 Null pointer Exception 없이 사용하는 습관 [JAVA] equals 메서드 Null pointer Exception 없이 사용하는 습관 2021.07.24 - [인턴업무] - [HTML5] 타임리프 -..

ktae23.tistory.com

 

 

이전까지는 컨트롤러 -> 서비스 -> 매퍼 -> 서비스 -> 컨트롤러 -> 반환 순의 아주 정직한 요청만 처리해봤었다.

 

하지만 이번에 해야했던 업무는 사용자 리스트를 뽑고 각 사용자가 가지고 있는 학습 데이터를 원하는 기준으로 짤라서 가져와야 했다.

 

데이터베이스 여기저기에 흩뿌려져 있는 데이터를 모아 가공하여 원하는 결과를 만들어 내야하는데, 계산에 필요한 데이터가 서로 엉켜있어서 서비스 로직을 깔끔하게 나눌 수도 없는 노릇이었다.

 

<사용자 리스트>, <학습 점수>, <학습 진행 정보>을 가져와야하는데 각 데이터의 개수도 천차만별이라 이를 사용자 별로 구분하는 것이 난관이었다.

 


 

이를 해결하기 위한 방법으로 생각한 것은

 

1.  원하는 데이터를 모두 쿼리문으로 뽑아내어 DB에 VIEW를 만든다.

 

2. 각 서비스와 매퍼에서 정보를 가져와 List<사용자 리스트>, List<학습 점수>, List<학습 진행 정보>을 필드 값으로 갖는 클래스로 감싸서 반환 한다.

 

3. 빌더 패턴을 사용해 원하는 정보를 가공 하여 넣어 준다.

 

 


 

 

1번은 DB에 요청하는 데이터가 테이블 마다 흩뿌려져 있기 때문에 쓰레기 값이 많이 섞여와서 사용자별로 데이터를 구분하기 어려워서 패스

 

2번 역시 사용자별로 구분하기 어려워서 패스

 

선택한 방법은 3번을 아래의 순서로 진행.

 

1. List<사용자 리스트>, List< 학습 점수>, List<학습 진행 정보>를 각각 DB에서 호출.

 

2. 사용자 List를 순환하며 각 사용자마다 해당하는 학습 정보를 DB에서 호출하고 필요한 계산을 진행.

 

3. 계산된 값을 builder 패턴으로 반환 객체를 생성하여 꽂아주어 반환.

 

 

빌더 패턴은 각 경우의 수에 대한 생성자를 모두 만들어주지 않거나 세팅 순서가 바뀌더라도 이에 대응 할 수 있다는 장점이 있다.

또한 빌더 패턴을 사용하면 매퍼에서 가져오는 반환 객체를 그대로 반환하지 않는 경우에 유용한데, 이는 아래 예시를 참고하자.

 

 

사용자 반환값을 담기 위한 userListDto 객체 <- 프론트로 값을 반환 할 때 감싸는 용도로 사용한다.

import com.openeg.openegscts.group.entity.GroupUsersList;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@NoArgsConstructor
public class usersListDto {

    private String userName;
    private String userId;

    private String courseName;

    private int resultLowCount;
    private int resultMiddleCount;
    private int resultHighCount;

// Lombok을 사용하면 이처럼 AllArgumentConstructor에 
// 어노테이션을 하나 붙이는걸로 쉽게 빌더 패턴을 생성하여 사용할 수 있다.
    @Builder 
    public GroupUsersListDto(String userName, String userId, String courseName,
                             int resultLowCount, int resultMiddleCount, int resultHighCount) {
        this.userName = userName;
        this.userId = userId;
        this.courseName = courseName;
        this.resultLowCount = resultLowCount;
        this.resultMiddleCount = resultMiddleCount;
        this.resultHighCount = resultHighCount;
    }


}

 

 

서비스 로직

 @Override
    public List<usersListDto> getUsersForOperator(String userId) {
    	// 팀 운영자의 사용자 정보 가져오기
        Users operator = iUserMapper.getUserById(userId);
        // 반환을 위한 리스트 생성
        List<usersListDto> returnList = new ArrayList<>();
        // 팀 운영자의 정보를 이용해 운영자가 속한 팀의 팀원 리스트 가져오기
        List<usersList> usersList = iUsersMapper.getUsersForOperator(operator.getTeamId());
		
        //팀원의 수 만큼 진행
        for (usersList ul : usersList) {
        
        	// 팀원의 사용자 정보 가져오기
            Users user = iUserMapper.getUserById(ul.getUserId());
            
            // 팀원의 학습 점수 가져오기 (필요한 계산은 ScoreService에서 진행 됨)
            ScoreDto scoreDto = iScoreService.getScoreById(user);
            
            // 팀원의 학습 진행 정보 가져오기 (필요한 계산은 CourseProgressService에서 진행 됨)
            CourseProgressDto courseProgressDto = iCourseProgressService.getCourseProgressById(user);


			// 반환을 위한 객체 생성 -> 빌더 패턴 이용
            usersListDto uld = usersListDto.builder()
                    .userId(ul.getUserId())
                    .userName(ul.getUserName())

                    .courseName(courseProgressDto.getCourseName())

                    .resultHighCount(scoreDto.getresultHighCount())
                    .resultMiddleCount(scoreDto.getresultMiddleCount())
                    .resultLowCount(scoreDto.getresultLowCount())

                    .build();
                    
            // 반환 할 리스트에 객체 추가
            returnList.add(uld);
        }
        return returnList;
    }

 

 

+ Lombok이 생성해주는 빌더 패턴 모습

public class UsersListDto {

    String userName;
    String userId;
    String courseName;
    int resultLowCount;
    int resultMiddleCount;
    int resultHighCount;


    UsersListDto(final String userName,final String userId, final String courseName, final int resultLowCount, final int resultMiddleCount, final int resultHighCount) {
        this.userName = userName;
        this.userId = userId;
        this.courseName = courseName;
        this.resultLowCount = resultLowCount;
        this.resultMiddleCount = resultMiddleCount;
        this.resultHighCount = resultHighCount;
    }

    public static UsersListDto.UsersListDtoBuilder builder() {
        return new UsersListDto.UsersListDtoBuilder();
    }

    public static class UsersListDtoBuilder{

        private String userName;
        private String userId;
        private String courseName;
        private int resultLowCount;
        private int resultMiddleCount;
        private int resultHighCount;

        UsersListDtoBuilder(){}

        public UsersListDtoBuilder userName(final String userName) {
            this.userName = userName;
            return this;
        }

        public UsersListDtoBuilder userId(final String userId) {
            this.userId = userId;
            return this;
        }

        public UsersListDtoBuilder courseName(final String courseName) {
            this.courseName = courseName;
            return this;
        }

        public UsersListDtoBuilder resultLowCount(final int resultLowCount) {
            this.resultLowCount = resultLowCount;
            return this;
        }

        public UsersListDtoBuilder resultMiddleCount(final int resultMiddleCount) {
            this.resultMiddleCount = resultMiddleCount;
            return this;
        }

        public UsersListDtoBuilder resultHighCount(final int resultHighCount) {
            this.resultHighCount = resultHighCount;
            return this;
        }

        public UsersListDto build (){
            return new UsersListDto(this.userName, this.userId,  this.courseName, this.resultLowCount, this.resultMiddleCount, this.resultHighCount);
        }

    }

}

 

+ Lombok 없이 사용하는 빌더 패턴

import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

public class UsersListDto {

    private String userName;
    private String userId;
    private String courseName;
    private int resultLowCount;
    private int resultMiddleCount;
    private int resultHighCount;


    public String getUserName() {
        return userName;
    }

    public String getUserId() {
        return userId;
    }

    public String getCourseName() {
        return courseName;
    }

    public int getResultLowCount() {
        return resultLowCount;
    }

    public int getResultMiddleCount() {
        return resultMiddleCount;
    }

    public int getResultHighCount() {
        return resultHighCount;
    }



    private UsersListDto(UsersListDtoBuilder builder) {
        this.userName = builder.userName;
        this.userId = builder.userId;
        this.courseName = builder.courseName;
        this.resultLowCount = builder.resultLowCount;
        this.resultMiddleCount = builder.resultMiddleCount;
        this.resultHighCount = builder.resultHighCount;

    }

    public static class UsersListDtoBuilder{

        private String userName;
        private String userId;
        private String courseName;
        private int resultLowCount;
        private int resultMiddleCount;
        private int resultHighCount;

        public UsersListDtoBuilder builder() {
            return this;
        }
//        또는 필수 입력 필드를 강제 할 수 있다.
//        public UsersListDtoBuilder builder(String userName) {
//            this.userName = userName;
//            return this;
//        }


        public UsersListDtoBuilder userName(String userName) {
            this.userName = userName;
            return this;
        }

        public UsersListDtoBuilder userId(String userId) {
            this.userId = userId;
            return this;
        }

        public UsersListDtoBuilder courseName(String courseName) {
            this.courseName = courseName;
            return this;
        }

        public UsersListDtoBuilder resultLowCount(int resultLowCount) {
            this.resultLowCount = resultLowCount;
            return this;
        }

        public UsersListDtoBuilder resultMiddleCount(int resultMiddleCount) {
            this.resultMiddleCount = resultMiddleCount;
            return this;
        }

        public UsersListDtoBuilder resultHighCount(int resultHighCount) {
            this.resultHighCount = resultHighCount;
            return this;
        }

        public UsersListDto build (){
            return new UsersListDto(this);
        }

    }

}
반응형

댓글