Programming/Java

Java 빌더 패턴 (Builder Pattern)이란?

Jan92 2021. 8. 22. 00:03

Builder Pattern

 

Java 빌더 패턴 (Builder Pattern) 이란?

 

Java에서는 클래스를 객체화하는 '점층적 생성자 패턴', '자바 빈즈 패턴', '빌더 패턴' 3가지 패턴이 존재합니다.

 

 

https://wildeveloperetrain.tistory.com/29

 

(Java) 점층적 생성자 패턴 & 자바 빈즈 패턴

프로그래밍에서 Class를 설계하다 보면, 필수로 받아야 할 인자와 선택적으로 받아야 할 인자가 구분됩니다. 그리고 Java에서는 이렇게 설계된 다양한 형태의 Class들을 객체화하는 3가지 패턴이 존

wildeveloperetrain.tistory.com

 

이전 포스팅의 점층적 생성자 패턴, 자바 빈즈 패턴에 이어 점층적 생성자 패턴의 안전성과 자바 빈즈 패턴의 가독성을 더한 빌더 패턴 (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 어노테이션에 주석 처리된 예시 코드입니다.