티스토리 뷰

Java

builder pattern 에 대한 고찰

LichKing 2022. 4. 23. 19:16

요즘 자바코드를 보면 클래스를 정의할때 무조건적으로 builder pattern 을 적용하는걸 심심찮게 볼 수 있다. 회사코드에서도 그렇게 작성된 코드를 쉽게 접하기도 한다. 더욱이 롬복에서 @Builder 라는, 아주 간편하게 빌더 클래스를 만들어주는 기능을 제공해주다보니 빌더 클래스를 만드는 것에 대한 부담도 없다.

@Builder
class Person {
  private String name;
  private int age;
}

사용하는 쪽에선 이렇게 사용한다.

Person p = Person.builder()
  .name("LichKing")
  .age(34)
  .build();

언제부턴가 이렇게 빌더패턴이 거의 디폴트가 되다시피 한거같은데 개인적인 추측으로는 빌더패턴이 이렇게 퍼지게된건 이펙티브 자바의 역할이 크다고 본다.

아이템 2. 생성자에 매개변수가 많다면 빌더를 고려하라 

 

물론 필요하면 당연히 써야한다고 생각하지만 나는 무조건적으로 @Builder 를 붙이는걸 좋아하지않는데 그 이유를 정리해보려한다.

 

1. 강결합

객체지향언어에서 중요한 덕목 중 하나는 캡슐화이다. 그런데 빌더패턴을 사용하면 그 자체로 내부 정보들이 모조리 다 공개되게된다. 객체 내부의 필드가 추가되거나 삭제되면 해당 클래스를 사용하는 모든 코드에 영향을 준다. 심지어 필드명만 바꿔도 모든 코드에 영향을 준다.

 

2. 가독성

빌더패턴을 애용하고있다면 현업코드에서도 어렵지않게 아래와 같은 코드를 볼 수 있을 것이다.

public class SomeService {
  public void someMethod() {
    SomeType instance = someClass.builder()
      .field1()
      .field2()
      .field3()
      .field4()
      .field5()
      .build();
  
    // 실제 비즈니스 코드 2~3줄
  }
}

해당 서비스 메서드에서 실제로 하는 행위는 몇줄 안되는데 빌더패턴이용시 파라미터를 개행으로 처리하다보니 빌더 코드로만 비즈니스 행위 이상의 라인을 차지하게된다. 코드의 가독성이 좋지않아지는건 당연하다.

 

3. 원자적 생성

빌더패턴으로는 완전한 객체생성의 원자성을 보장하기어렵다. 실제로 위 Person 객체를 생성하기 위해선 age 와 name 모두 필수 값이라고 가정해보자.

Person.builder()
  .build();

그렇다고해도 age 와 name 에 값을 넣지않는 이런 코드를 막을 순 없다. 롬복이 만들어주는 빌더말고 직접 빌더를 만들어 사용하더라도 런타임 에러를 낼 수 있을뿐 컴파일 타임에 체크하기는 어렵다. 생성자를 이용하면 이런 제약사항을 표현할 수 있다.

// 필드중 하나라도 누락시 컴파일 타임에 에러를 만나게 된다
new Person("LichKing", 34);

 

결론

이펙티브자바에서는 빌더를 애용하라는 형태의 격언을 하고있다. 특히 필드가 많아지면 이처럼 유용한게 없다고 표현한다. 하지만 객체에 그 정도로 필드가 많아지면 객체 디자인을 고민해봐야할때가 아닌가싶다.

 

그래도 분명 빌더가 유용한 경우가 있을 것이다. 하지만 나는 위와 같은 이유로 인해 무조건적인 빌더 생성을 선호하지 않는다. 빌더를 붙일땐 이 객체 생성시 왜 빌더가 필요한지 이유를 설명할 수 있어야 한다고 생각한다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함