빌드패턴, lombok의 @Builder

2021. 1. 26. 15:24SPRING/SPRING CORE

빌드패턴이란?

객체를 생성하고 필드에 값을 주입하는 방법에는 대표적으로 3가지 방법이 있다. (추가내용: 정적 팩토리 메서드 패턴도 존재하지만 이 포스트에서는 다루지 않음)

1. 생성자 주입

Member member = new Member("윤빙구", 33, "경기도");

2. 객체 생성 후 setter로 주입

Member member = new Member();
member.setName("윤빙구");
member.setAge(33);
member.setAddress("경기도");

3. 빌드패턴으로 주입

Member member = Member.builder()
		.name("윤빙구")
		.age(33)
		.address("경기도")
		.build();

빌드패턴은 이렇게 객체를 생성하면서 필드에 값을 주입하는 방법 중 하나이다.

근데 이걸 왜 쓰는걸까? 궁극적으로 이 질문에 답을 찾기 위해 먼저 빌드패턴을 구현하는 방법을 알아보자.

빌드패턴 구현 방법

@Getter
public class Member {
	
	private String name;
	private int age;
	private String address;
    
    private Member(MemberBuilder builder) {
		this.name = builder.name;
		this.age = builder.age;
		this.address = builder.address;
	}
	
	public static MemberBuilder builder() {
		return new MemberBuilder();
	}
	
	public static class MemberBuilder {
		
		private String name;
		private int age;
		private String address;
		
		public MemberBuilder name(String name) {
			this.name = name;
			return this;
		}
        
		public MemberBuilder age(int age) {
			this.age = age;
			return this;
		}
        
		public MemberBuilder address(String address) {
			this.address = address;
			return this;
		}
        
		public Member build() {
			return new Member(this);
		}		
	}
}
  • Member 클래스는 생성자와 setter에 대해 열어두지 않는다.
  • MemberBuilder가 필드에 값을 세팅하여 Member 객체에 전달해주고 객체를 생성하여 반환한다.
  • setter에 닫혀있는것은 불변객체라고 할 수 있다. 불변 객체는 해당 객체를 여러 곳에서 사용할 때 값을 변경할 수 없도록 하여 안전하게 사용할 수 있도록 하는 것이다.
  • 그럼 setter를 사용하지 않고 생성자 주입으로만 사용하면 되는것이 아닌가?
  • 빌드패턴은 생성자 주입시 여러가지 단점도 보안한다.
  1. 1. 생성자에서 받는 필드를 선택하여 사용한다. 예를 들어 요구사항이 변경되어 필드가 추가되었을 경우, 생성자에서 받는 인자를 하나 더 추가해야하는 상황을 피할 수 있다. 또한 생성자에서 값을 세팅하지 않아도 되어 null을 세팅하는 일이 없도록 방지할 수 있다.
  2. 2. 생성자에서 필드를 받는 경우 어떤 순서에 어떤 값이 들어가는지 파악하고 있어야 한다. 하지만 빌드 패턴은 마치 setter처럼 필드를 지정하여 값을 주입할 수 있다. 이것은 굉장히 명시적인 방법이다.

 

정리를 하면 빌드패턴을 사용하는 이유는

setter에 닫혀있는 불변객체로 사용하면서 생성자 주입에 대한 단점을 보안하기 위해 사용한다.

 

무조건 사용하면 좋다고 말할 수 없으며 무분별하게 사용할 경우 내부 클래스에 의해 쓸데없이 메모리 낭비가 되니 상황에 맞게 사용해야한다.(JPA의 임베디드 타입에 사용하는 것이 적절하게 사용한 경우인 것 같다.)

lombok의 @Builder

빌더 패턴을 구현하기 위해 저렇게 긴 코드를 작성할 필요는 없다. lombok의 @Builder 어노테이션을 사용하자.

@Getter
public class Member {
    private String name;
    private int age;
    private String address;

    @Builder
    public Address(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }
}