티스토리 뷰

Server

[Java] Model과 Lombok(Builder)

니용 2020. 2. 12. 11:56
반응형

Builder(커욥)

 

이전에 Annotation 글을 작성하면서 Lombok에 대해 간단히 정의해보았었습니다.

이전에는 전반적인 Annotation들에 대해 설명하게 되면서 lombok은 생략이 되었었는데요, 

이번 글에서는 현재 제가 실무에 사용하고 있는 lombok에 대해 정리해보려고 글을 작성하게 되었습니다.

 

먼저, IntelliJ 기준의 lombok의 사용법은 다음과 같습니다. 

gradle 기반의 프로젝트이며 dependencies 에 다음과 같이 추가하면 사용할 수 있습니다.

 

dependencies {
    ...
    compileOnly('org.projectlombok:lombok')
    annotationProcessor('org.projectlombok:lombok')

    ...
}


간혹의 경우 lombok을 implementation으로 지정하는 경우도 있는데,

이는 jar파일이 빌드가 되었을 때 모델을 class 파일로 저장하는 것이 크게 의미가 없기에 compile로 지정을 하였고,

compileOnly로 구현하여도 다른 문제가 발생하지 않아 적용하였습니다.

 

annotationProcessor는 프로젝트를 export하는 시점에 lombok에서 제공되는 Annotation들이 전부 포함되지 않기에 추가하게 되었습니다. (이 글을 참고하시면 더 좋을듯해요!)

 

댓글을 모델로 하여 구현을 하는 과정에서 모델 클래스를 아래와 같이 정의해보았습니다.

public class Reply {
    private int replyId;
    private int parentReplyId;
    private String userName;
    private String imageUrl;
    private String text;
    private List<Reply> childList;
}

 

아직 Lombok과 관련된 어노테이션이 설정되어 있지 않은데요, 여기서 작업 전에 설정을 하나 하셔야 합니다.

Settings에 'Annotation Processor' 검색을 해봅니다.

위치는 'Build, Execution, Deployment -> Compiler' 내에 존재합니다. 

여기에서 Enable annotation processing에 체크를 하면, Lombok Annotation 외에 추가 Annotation 들도 사용이 가능한 상태로 변하게 됩니다.

 

설정이 완료되었다면 모델 클래스로 돌아와서 다음과 같이 추가해줍니다.

 

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


@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Reply {
    private int replyId;
    private int parentReplyId;
    private String userName;
    private String imageUrl;
    private String text;
    private List<Reply> childList;
}

@Data: setter, getter를 생성해줍니다.

@Builder: Builder Pattern 사용을 가능하게 해줍니다.

@NoArgsConstructor: 파라미터가 없는 기본 생성자를 생성해줍니다. ex) new Reply();

@AllArgsConstructor: 모든 property 파라미터를 가진 기본 생성자를 생성해줍니다.

ex) new Reply(int replyId, int parentReplyId, String userName, String imageUrl, String text, List<Reply> childList);

 

여기서 클라이언트 측에서는 사용도가 없는 replyId, parentReplyId를 보이지 않도록 처리하겠습니다.

@JsonIgnore를 사용합니다.

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import com.fasterxml.jackson.annotation.JsonIgnore;


@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Reply {
    @JsonIgnore private int replyId;
    @JsonIgnore private int parentReplyId;
    private String userName;
    private String imageUrl;
    private String text;
    private List<Reply> childList;
}


@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
class ReplyModel {
    private boolean success;
    private String message;
    private List<Reply> model;
}

이제 특정 서비스에서 해당 모델에 관해 구현하는 방법을 알아보겠습니다.

 

기존의 방법은 아래와 같이 구현하였을 것입니다.

@Service
public class ReplyService {
    @JsonIgnore ReplyMapper replyMapper;
    public ReplyModel  getReplyList(Map<String, Object> param){
        ReplyModel returnValue = new ReplyModel();
        try {
            int depth = Integer.parseInt(param.get("depth"));
            List<Reply> model = replyMapper.selectReplyList(param));
            if(depth == 2) {
                for(int i=0; i<model.size(); i++) {
                    param.put("parentReplyId",model.get(i).getReplyId());
                    param.put("selectDepth", depth);
                    List<Reply> child = replyMapper.selectReplyChildList(param);
                    model.setChildList(child);
                }
            }
            returnValue.setSuccess(true);
            returnValue.setMessage("정상 호출");
        } catch (Exception e) {
            returnValue.setSuccess(false);
            returnValue.setMessage("에러가 발생했습니다.");
        }
       return returnValue;
    }


}

기존에는 일일히 Setter를 사용하여 모델을 정제하고 처리하였습니다.

Builder를 사용하면 이를 간소화시키기 용이합니다.

이전 글에서 언급한 바와 같이 Builder는 Chaining을 기반으로 작성된 자바 라이브러리입니다.

쉽게 말해서 쩜(.)으로 연속적으로 이어서 사용할 수 있다는 장점이 있습니다.

사용 방법은 아래와 같습니다.

ReplyModel replyModel = ReplyModel.builder().build();  // new ReplyModel();로 선언한 것과 같습니다

하지만 이렇게 Builder를 사용하면 크게 의미가 없습니다. 결국 뒤에서 setter를 사용하기 때문이죠.

Builder에 장점은 아래의 소스에서 나오게 됩니다.

ReplyModel.builder().success(true).message("정상 호출").model(model).build();

이와 같이 모델에 적용되어 있는 Property들을 각각의 Method화 되있는 녀석들을 연속적으로 호출할 수 있습니다.

위에 적어두었던 소스를 Builder 패턴을 사용하여 변경해보도록 하겠습니다.

(Lambda 식도 살짝 곁들었습니다)

@Service
public class ReplyService {
    @JsonIgnore ReplyMapper replyMapper;
    public ReplyModel  getReplyList(Map<String, Object> param){
        try {
            int depth = Integer.parseInt(param.get("depth"));
            if(depth == 2) {
                param.put("selectDepth", depth);
                return ReplyModel.builder()
                    .success(true)
                    .message("정상 호출")
                    .model(
                        replyMapper.selectReplyList(param)).stream()
                        .filter(Objects::nonNull)
                        .peek(reply -> {
                            param.put("parentReplyId",model.get(i).getReplyId());
                            param.put("selectDepth", depth);
                            reply.setChildList(replyMapper.selectReplyChildList(param));
                        })
                        .collect(Collectors.toList()))
                   .build();
            }
        } catch (Exception e) { }
       return ReplyModel.builder()
            .success(false)
            .message("에러가 발생했습니다.");
    }
}

이와 같은 형식으로 변경하면 많은 변수의 선언 없이 적용이 가능합니다.

 

Builder 패턴을 사용하는 이유는 크게 3가지입니다.

1. 가독성을 높일 수 있습니다.

2. 인자가 많을 경우 쉽고 안전하게 객체를 생성 가능하게 해줍니다.

3. 순서에 관계없이 객체를 생성할 수 있습니다.

 

참고: https://ko.wikipedia.org/wiki/%EB%B9%8C%EB%8D%94_%ED%8C%A8%ED%84%B4

 

빌더 패턴 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 빌더 패턴이란 복합 객체의 생성 과정과 표현 방법을 분리하여 동일한 생성 절차에서 서로 다른 표현 결과를 만들 수 있게 하는 패턴이다. 2 단어 요약 : 생성

ko.wikipedia.org

 

반응형

'Server' 카테고리의 다른 글

MySQL 함수(SUBSTR, DATE_FORMAT, CAST)  (0) 2020.04.22
[Java] 타입 변환  (0) 2020.04.17
Firebase 알아보기  (0) 2020.04.07
[Java] MultipartFile 를 이용하여 파일 업로드하기  (0) 2020.01.28
[Java] Cron 표현식  (0) 2019.12.19
SQL에 대해 알아보자  (0) 2019.12.15
댓글
공지사항