-
[Spring] Lombok을 이용해 Builder 패턴을 만들어보자.웹 개발/Spring Framework 2020. 3. 21. 17:10
Builder 패턴이란?
Effective Java 규칙 2 - 조슈아 블로크
생성자에 인자가 많을 때는 빌더 패턴을 고려하라
빌더 패턴(Builder pattern) 이란 복합 객체의 생성 과정과 표현 방법을 분리하여 동일한 생성 절차에서 서로 다른 표현 결과를 만들 수 있게 하는 패턴이다. (출처: 위키백과)
난 생성자가 많아지면 빌더 패턴을 만드는 편인데, 개발자 성향에 따라 다를수도 있구나를 느꼈다.
빌더패턴을 활용하면 어떤 필드에 어떤 인자를 넣어줬는지 명확히 알 수 있고, 넣어줄 필요 없는 필드(null)는 굳이 선언할 필요 없으니 좋다고 생각했다. 근데 다른 분은 어떤 필드에 null이 들어간다는걸 명확히 볼 수 있는 점 때문에 생성자를 통해 객체를 생성하시는 방법을 택했다고 하셨다.
intelliJ는 들어갈 필드의 값을 표시해주는 기능이 있어서 생성자를 통해 객체를 생성해도 어떤 필드를 넣어줘야하는지 보인다. 첫 회사에서는 STS를 썼기 때문에 intelliJ의 다양한 기능적인 혜택을 누리지 못했기도 해서 빌더 패턴이 유용했다.
코틀린을 사용할 경우에는.... 굳이 빌더 패턴을 쓸 필요가 없을 것 같다 싶었던 이유가 생성자 인자에 필드 명도 함께 표기할 수 있다.
// 예시 fun foo() { val member = Member(name = "zorba", job = "developer") }
하지만, java를 쓸 때는 자주 사용하는 디자인 패턴이다.
빌더 패턴의 장점
1. 객체들마다 들어가야할 인자가 각각 다를 때 유연하게 사용할 수 있다.
2. 무조건 setter 생성을 방지하고 불변객체로 만들 수 있다.
3. 필수 argument를 지정할 수 있다.(보통의 경우, PK 역할을 할 Id 값이 될 것이다.)
Builder 패턴은 어떻게 작성하나?
이 페이지를 들어가면 명확하게 빌더 패턴을 어떻게 작성해야하는지 알 수 있다. 빌더 패턴 예제코드
Java 사용자라면 잘 아는 StringBuilder가 이 빌더 패턴으로 작성된 라이브러리다.
근데 클래스를 만들 때마다 이 기나긴 코드를 짜기 불편하다!
그래서 Java 개발자들의 보일러플레이트 코드를 획기적으로 줄여준 라이브러리인 Lombok을 활용해보자.
바로 @Builder 애노테이션 을 사용하면 예제코드처럼 긴 코드를 작성하지 않아도 된다.
Builder 패턴을 적용할 클래스
@AllArgsConstructor(access = AccessLevel.PRIVATE) @Builder(builderMethodName = "travelCheckListBuilder") @ToString public class TravelCheckList { private Long id; private String passport; private String flightTicket; private String creditCard; private String internationalDriverLicense; private String travelerInsurance; public static TravelCheckListBuilder builder(Long id) { if(id == null) { throw new IllegalArgumentException("필수 파라미터 누락"); } return travelCheckListBuilder().id(id); } }
확인용 클래스
public class MainClass { public static void main(String[] args) { // 빌더패턴을 통해 어떤 필드에 어떤 값을 넣어주는지 명확히 눈으로 확인할 수 있다! TravelCheckList travelCheckList = TravelCheckList.builder(145L) .passport("M12345") .flightTicket("Paris flight ticket") .creditCard("Shinhan card") .internationalDriverLicense("1235-5345") .travelerInsurance("Samsung insurance") .build(); System.out.println("빌더 패턴 적용하기 : " + travelCheckList.toString()); } // 결과 // 빌더 패턴 적용하기 : TravelCheckList(id=1, passport=M12345, flightTicket=Paris flight ticket, creditCard=Shinhan card, internationalDriverLicense=1235-5345, travelerInsurance=Samsung insurance) }
@AllArgsConstructor(access = AccessLevel.PRIVATE) : @Builder 애노테이션을 선언하면 전체 인자를 갖는 생성자를 자동으로 만든다. @AllArgsConstructor는 전체 인자를 갖는 생성자를 만드는데, 접근자를 private으로 만들어서 외부에서 접근할 수 없도록 만든다.
@Builder : 위에서 설명했던 Builder 패턴을 자동으로 생성해주는데, builderMethodName에 들어간 이름으로 빌더 메서드를 생성해준다. 나같은 경우, 혼동을 줄이기 위해 클래스 명과 동일하게 놔두고 Builder로 선언했다.
클래스 내부 builder 메서드 : 필수로 들어가야할 필드들을 검증하기 위해 만들었다. 꼭 id가 아니라도 해당 클래스를 객체로 생성할 때 필수적인 필드가 있다면 활용할 수 있다.
이렇게 Lombok을 활용하면 반복적으로 길게 짜야하는 코드(보일러 플레이트 코드)를 엄청나게 줄여줄 수 있다.
빌더 패턴을 사용하면서 무분별한 setter를 남용한다면.... 빌더패턴의 장점을 극대화해서 사용하는 건 아닌 것 같다.
'웹 개발 > Spring Framework' 카테고리의 다른 글
[Spring Boot] logback과 Sentry를 활용하여 에러 모니터링하기 (0) 2020.05.30 [Spring] 팩토리 메소드 패턴을 적용하여 bean을 동적으로 사용하기 (5) 2020.04.19 [Spring] 페이징처리를 위해 써먹는 Paging 객체 만들기 및 활용 (0) 2019.05.18 [Spring] war에 test class가 포함된다?(war에서 test class 빼는 법) (0) 2019.05.08 [Spring Boot, Gradle] gradle dependency 전체 삭제하는 법(gradle build 에러 해결 방법) (0) 2019.03.08