@Builder 빌더 패턴에 대해 알아보자

wony·2024년 11월 22일

Spring

목록 보기
33/33

프로젝트를 하던 중 만난 @Builder.. 사용하니 테스트 코드를 작성하는데 굉장히 유용하여 따로 정리해보려고 한다.

빌더 패턴(Builder pattern)이란?

객체를 정의하고 그 객체를 생성할 때 보통 생성자를 통해 생성하는 것을 생각한다. 하지만 생성자를 통해 객체를 생성하는데 몇 가지 단점이 있어 객체를 생성하는 별도 builder를 두는 방법이 있다.

// 생성자를 통해 생성
Bag bag = new Bag("name", 1000, "memo");
Bag bag = Bag.builder()
			.name("name")
            .money(1000)
            .memo("memo")
            .build();

객체를 생성할 수 있는 빌더를 builder() 함수를 통해 얻고 거기에 셋팅하고자 하는 값을 셋팅하고 마지막에 build()를 통해 빌더를 작동시켜 객체를 생성한다.

빌더의 장점

  1. 생성자 파라미터로 받아야 하는 값이 많을 경우 가독성이 좋지 않다.
// 많으면 뭐가 뭔지 알기 어렵다.
Bag bag = new Bag("name", 1000, "memo", "abc", "what", "is", "it", "?");

하지만 이를 빌더 패턴으로 구현하면 각 값들은 빌더의 각 값들의 이름 함수로 셋팅이 되지 각각 무슨 값을 의미하는지 파악하기 쉽다. 따라서, 생성자로 설정해야하는 값이 많을 경우 빌더를 쓰는 것이 생성자보다 가독성이 좋다.

Bag bag = Bag.builder()
			.name("name")
        	.money(1000)
        	.memo("memo")
            .letter("This is the letter")
            .box("This is the box")
        	.build();
  1. 어떤 값을 먼저 설정하던 상관 없다.

생성자의 경우는 정해진 파라미터 순서대로 꼭 값을 넣어줘야 한다. 순서를 무시하고 값을 넣으면 에러가 발생하거나 엉뚱한데 값이 들어갈 수 있다.

public Bag(String name, int money, String memo) {
		this.name = name;
    	this.money = money;
    	this.memo = memo;
}

하지만, 빌더 패턴은 빌더의 필드 이름으로 값을 설정하기 때문에 순서에 종속적이지 않다. 어떤 필드를 먼저 설정해야하는지 굳이 순서를 생각할 필요 없이 설정하면 된다.

Bag bag = Bag.builder()
		.name("name")
        	.memo("memo")	// memo를 money 대신 먼저!
        	.money(1000)
        	.build();

@Builder

  • 위와 같은 이유로 생성자 대신 빌더를 사용하곤 하는데 롬복의 @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 어노테이션을 달기만 하면 된다.

@Builder
public class Bag {
	private String name;
        private int money;
        private String memo;
}

어노테이션만 달면 빌더가 생기고 위에 썼던 것과 같이 빌더를 통해 객체를 생성할 수 있다.

Bag bag = Bag.builder()
			.name("name")
        	.money(1000)
        	.memo("memo")
        	.build();
profile
안녕하세요. wony입니다.

0개의 댓글