Java 빌더 패턴 (Builder Pattern) 이란?
Java에서는 클래스를 객체화하는 '점층적 생성자 패턴', '자바 빈즈 패턴', '빌더 패턴' 3가지 패턴이 존재합니다.
https://wildeveloperetrain.tistory.com/29
이전 포스팅의 점층적 생성자 패턴, 자바 빈즈 패턴에 이어 점층적 생성자 패턴의 안전성과 자바 빈즈 패턴의 가독성을 더한 빌더 패턴 (Builder Pattern)에 대해서 알아보겠습니다.
public class Member {
private String name;
private int age;
private String address;
private String phone;
private Member(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.address = builder.address;
this.phone = builder.phone;
}
// 빌더 호출, 외부에서 Member.builder() 으로 접근할 수 있도록 static 메소드로 생성
public static Builder builder() {
return new Builder();
}
// static 형태의 inner class 생성
public static class Builder {
private String name;
private int age;
private String address;
private String phone;
private Builder() {};
public Builder name(String name) {
this.name = name;
return this;
}
public Builder age(int age) {
this.age = age;
return this;
}
public Builder address(String address) {
this.address = address;
return this;
}
public Builder phone(String phone) {
this.phone = phone;
return this;
}
// 마지막에 build 메소드를 실행하면 this가 return 되도록 구현
public Member build() {
return new Member(this);
}
}
}
Build Pattern을 사용할 클래스는 위와 같이 구현할 수 있으며,
Member member = Member.builder()
.name("jan")
.age(99)
.address("jan")
.phone("010")
.build();
다음과 같이 사용할 수 있습니다.
코드를 보면 각 매개변수를 넣어주는 메서드의 리턴 자료형을 Builder 객체로 지정함으로써, 메서드 체이닝 기법을 적용하고, 매개변수를 다 넣은 경우 build() 메서드로 객체를 생성합니다.
이렇게 빌더 패턴을 사용하면 어느 필드에 어떤 값을 채워야 할지 명확하게 알 수 있으며, 데이터 일관성, 객체 불변성 등을 만족시키며 코드의 가독성 또한 올라갑니다.
* Member 클래스에는 setter 메서드와 public 생성자가 없기 때문에 Member 객체를 얻기 위해서는 오직 Builder 클래스를 통해서만 가능합니다.
하지만 빌드 패턴은 구현시 많은 코드양이 필요하고, Builder라는 객체를 하나 더 만드는 것이기 때문에 사용하는 코드에 따라 성능이 낮아질 수 있습니다.
따라서 클래스를 설계할 때 필수, 선택 인자들이 많은 경우 Builder 패턴을 사용하는 것이 효율적입니다.
+ 추가적으로
@Builder
public class Member {
private String name;
private int age;
private String address;
private String phone;
}
Lombok 라이브러리를 사용한다면 빌더 패턴을 사용할 클래스에 @Builder 어노테이션 하나만 적용해줌으로써 빌더 패턴을 사용할 수 있게 됩니다.
Before:
@Builder
class Example<T> {
private T foo;
private final String bar;
}
After:
class Example<T> {
private T foo;
private final String bar;
private Example(T foo, String bar) {
this.foo = foo;
this.bar = bar;
}
public static <T> ExampleBuilder<T> builder() {
return new ExampleBuilder<T>();
}
public static class ExampleBuilder<T> {
private T foo;
private String bar;
private ExampleBuilder() {}
public ExampleBuilder foo(T foo) {
this.foo = foo;
return this;
}
public ExampleBuilder bar(String bar) {
this.bar = bar;
return this;
}
@java.lang.Override public String toString() {
return "ExampleBuilder(foo = " + foo + ", bar = " + bar + ")";
}
public Example build() {
return new Example(foo, bar);
}
}
}
* 해당 코드는 @Builder 어노테이션에 주석 처리된 예시 코드입니다.
'Programming > Java' 카테고리의 다른 글
String class가 final인 이유, String의 불변성 (Immutable) (0) | 2021.08.24 |
---|---|
Static, Stack, Heap / Java 메모리 영역의 구조와 특징 (0) | 2021.08.23 |
(Java) 점층적 생성자 패턴 & 자바 빈즈 패턴 (0) | 2021.08.21 |
Java Primitive Type (원시 타입), Wrapper Class (래퍼 클래스) 차이점 (0) | 2021.08.04 |
Java 문자열을 다루는 클래스 String, StringBuilder, StringBuffer 차이점은 무엇일까? (1) | 2021.07.16 |