본문 바로가기
플러그인/Lombok

Builder 패턴 사용 시 주의점

by YellowCow 2023. 3. 16.

필드에 직접 리스트 초기화 불가

@Builder
@Data
public class Department{
    private String deptName;

    private User chief;

    private List<Employee> employees = new ArrayList<>();
}

 

업무 중에 위 코드의 경우와 같이 employees에 null값이 들어가는 것을 방지하기 위해

빈 List를 초기화하였다

 

단순하게 봤을 때 employees에 null이 아닌, 빈 List가 들어갈 것으로 보인다

 

하지만, 실제로는 빈 List가 아닌 null값이 들어가 있었다

employees가 초기화되지 않은 것이다

 

당시에 Builder패턴을 써서 객체를 생성하고 있었는데

디버깅을 하는 도중에

Builder 패턴을 써서 객체를 생성하지 않고

생성자로 객체를 생성하니까

employees에 의도한대로 빈 List가 초기화되는 것을 발견하였다

//Department객체의 employees에 null값이 들어간 경우
Department department = Department
                        .builder() //Department 빌더객체 생성
                        .build() //Department 객체 생성

//Department객체의 employees에 null값이 들어가지 않은 경우
Department department = new Department();

 

왜 그런 걸까?

먼저, Builder 패턴에 대해서 자세히 찾아봤다

Builder 패턴이 나온 배경에는 생성자의 한계 때문이다

생성자를 통한 객체생성에는 아래와 같은 한계가 있다

  • 생성자의 인자 순서에 맞춰서 인자값을 넘겨야 한다
    → 생성자를 사용하기 위해 전달되는 인자들의 순서를 알고 있어야 함
  • 초기화 하고자 하는 인자 수가 달라지면 생성자를 새로 만들어야 한다
  • 필요없는 인자에 대해서는 일일이 null값을 초기화 하여야 한다
  • 위 문제로 인해서 생성자 코드가 무거워진다

Builder 패턴에서는 위 문제를 해결하기 위해서

객체를 생성하는 Builder 객체를 별도로 만들고

Builder 객체에서 생성하고자 하는 객체를 생성하여 넘겨주는 방식으로

객체를 생성하고 있었다

 

아래는 Builder 코드 예시이다

DerpartmentBuilderImpl라는 Builder 클래스를 만들었다

public interface DerpartmentBuilder{
	void deptName(String deptName);

	void chief(User chief);

	void employees(List<Employee> employees);

	Department build();
}

 

public class DerpartmentBuilderImpl implements DerpartmentBuilder{
	private String deptName;

	private User chief;

	private List<Employee> employees;



	/* --------------------필드 값을 초기화 하는 부분------------------ */
	
	public void deptName(String deptName){
		this.deptName = deptName;
	}

	public void chief(User chief){
		this.deptName = deptName;
	}

	public void employees(List<Employee> employees){
		this.deptName = deptName;
	}
	
	/* ---------------------------------------------------------- */



	/* --------------------객체 생성 하는 부분----------------------- */
	
	public Department build()
		//DerpartmentBuilder에 있는 인자값을 이용하여 객체생성
		return new Department(deptName, chief, employees)
	}

	/* ---------------------------------------------------------- */
}

 

위 코드에서 DerpartmentBuilderImpl 클래스의 build() 메소드를 호출하면

DerpartmentBuilderImpl에서 갖고 있는 인자값을 이용하여 Department 객체를 생성한다

그렇기 때문에 Department의 employees를 초기화해도 

Builder 패턴을 이용해서 객체를 생성할 때, Builder 객체에 employees 값을 초기화해주지 않으면

DerpartmentBuilderImpl의 employees 값이 null이므로

Department의 employees가 null값으로 초기화되는 것이다

 

원래 의도한 대로 employees에 빈 list가 들어가게 하려면 아래 코드처럼 작성하면 된다

Department department = Department
                        //Department 빌더객체 생성
                        .builder() 
                        //employees 값 초기화
                        .employees(new ArrayList<>())
                        //Department 객체 생성
                        .build()

 

혹은 초기화 하려는 필드 위에 @Builder.Default를 적어주면

원하는 값으로 초기화 된다

@Builder
@Data
public class Department{
	private String deptName;

	private User chief;

	@Builder.Default
	private List<Employee> employees = new ArrayList<>();

}

 

*참고자료

https://dev-youngjun.tistory.com/197

댓글