빌더 패턴 (Builder Pattern)

컴공생의 코딩 일기·2023년 1월 4일
0

스프링

목록 보기
3/16
post-thumbnail

빌더 패턴 (Builder Pattern) 이란?

빌더 패턴은 복잡한 객체를 생성하는 방법을 정의하는 클래스와 표현하는 방법을 정의하는 클래스를 별도로 분리하여, 서로 다른 표현이라도 이를 생성할 수 있는 동일한 절차를 제공하는 패턴이다.

setter 메서드의 단점

  • setter 사용 의도를 알기 어렵다. 보통 setter 메서드는 setterXXX 메서드 이름으로 되어 있기 때문에 setterXXX로는 사용자가 무슨 용도로 사용하고자 하는지 유추하기 어렵다.
  • 자바빈 규약에 따르면 'getter, setter 메서드는 public 으로 선언되어야 한다.' 라고 한다 즉 언제 어디선든 값이 쉽게 변경될 수 있다.

  • 회원가입을 위해서 이름, 아이디, 비밀번호가 필수 값이라고 가정했을 때 setPwd 메서드에 값을 입력하지 않아도 Member 객체는 정상 적으로 작동한다. 즉 일관성이 없다.
  • settet 메서드를 사용할 경우 멤버 변수에 final 키워드를 사용할 수 없다.

생성자를 사용할 경우

Member member = new Member("홍길동", "id", "pwd", "test@email.com");

생성자를 통해 객체를 생성할 경우 여러가지 단점이 있다.

  1. 생성자 파라미터가 많을 경우 가독성이 좋지 않다.

    • 생성자의 파라미터가 많을 경우 이 값이 어떤 값인지 이해하기 힘들어진다.
  2. 생성자 파라미터의 순서를 반드시 지켜야한다.

    • 생성자 파라미터의 순서를 지키지 않을 경우 오류가 발생한다.
  3. 생성자에 설정하지 않는 값들은 전부 null로 채워져야 한다.

    • 생성자는 반드시 값을 설정해줘야 한다. 설정하지 않을 경우 컴파일 오류가 발생한다.

빌더 패턴 사용

public class Member {

    private String name;
    private String id;
    private String pwd;

    private Member(String name, String id, String pwd){
        this.name = name;
        this.id = id;
        this.pwd = pwd;
    }
    public static Builder builder(){
        return new Builder();
    }

      public static class Builder{
        private String name;
        private String id;
        private String pwd;

        public Builder name(String name){
            this.name = name;
            return this;
        }
        public Builder id(String id){
            this.id = id;
            return this;
        }
        public Builder pwd(String pwd){
            this.pwd = pwd;
            return this;
        }

        public Member build(){
            return new Member(name, id, pwd);
        }
    }

}
// builder 패턴 사용 코드
public class Main {
    public static void main(String[] args) {

        Member member = Member.builder()
                .name("name")
                .id("id")
                .pwd("pwd")
                .build();
    }
}

빌더패턴을 사용할 경우 가독성도 좋아질 뿐만 아니라 순서의 상관없이 파라미터를 설정할 수 있다.
메서드의 값을 넣지 않을 경우 null 값이 들어간다.

@Builder 어노테이션

롬복에서 지원하는 @Builder 어노테이션을 사용하면, 간단하게 빌더를 사용할 수 있다.

@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Member {
    private String name;
    private String id;
    private String pwd;
}
Member member = Member.builder()
                .name("name")
                .id("id")
                .pwd("pwd")
                .build();

클래스의 @Builder 어노테이션을 사용하면 해당 클래스의 모든 필드를 빌더 메서드로 사용가능 하다.

@NoArgsConstructor
@AllArgsConstructor

클래스의 @Builder 어노테이션을 사용할 경우 @NoArgsConstructor, @AllArgsConstructor 어노테이션을 함께 사용해야 한다.

public class Member {
    private String name;
    private String id;
    private String pwd;

    @Builder
    public Member(String id, String pwd){
        this.id = id;
        this.pwd = pwd;
    }
Member member = Member.builder()
                .id("id")
                .pwd("pwd")
                .build();

생성자에서 사용하게 되면 지정한 값만 메서드를 사용 가능하게 된다.

@Builder 속성

  1. builderMethodName

    @Builder 어노테이션을 사용하면 빌더를 생성하는 메서드의 이름은 기본 값인 builder()이다. 이를 새롭게 네이밍 할 수 있는 어노테이션 속성이다. (Default : builder())

  2. builderClassName

    @Builder를 사용하면 각 필드들의 값을 셋팅하는 메서드의 반환값의 빌더 클래스의 이름을 ...Builder로 자동 설정된다. 예를 들어 클래스 이름이 Member일 경우 @Builder의 적용된 반환 값이 MemberBuilder가 된다. 이걸 사용자가 원하는 대로 네이밍 하고 싶을때 builderClassName 속성을 사용한다.

  3. toBuilder

    boolean 값으로 설정할 수 있는 어노테이션으로 기본 값은 false이다. 이 값을 true로 설정 시 빌더로 만든 인스턴스에서 toBuilder() 메서드를 호출해 그 인스턴스 값을 베이스로 빌더 패턴으로 새로운 인스턴스를 생성할 수 있다. 기본값인 fasle로 설정할 경우 toBuilder() 메서드 자체가 존재하지 않을 경우 에러가 발생한다.

    Member member1 = Member.builder()
    				.name("홍길동")
        			.id("id")
        			.pwd("pwd")
        			.email("test@email.com")
        			.build();
                
    Member member2 = Member.toBuilder().name("홍길동").build();
  4. access()

    builder 클래스의 접근제어자를 어떻게 할 것인지에 대한 설정 값이다. (Default : public)

AccessLevel access() default lombok.AccessLevel.PUBLIC;
  1. @Builder.Default
    필드의 초기값 지정
@Builder
@ToString
public class Member {
    @Builder.Default private final String name = "name";
    private String id;
    private String pwd;
}
Member member = Member.builder()
                .id("id")
                .pwd("pwd")
                .build();

위 코드처럼 name 메서드에 값을 지정해주지 않으면 name 에는 null 값이 들어간다. 하지만 @Builder.Default 어노테이션으로 초기값을 지정해주면 "name" 값이 초기값으로 설정된다.
하지만 @Builder.Default 어노테이션을 사용하지 않고 값을 넣어도 결과는 똑같이 출력 된는데 음... 이건 다시 공부해야겠다...

  1. @Singular
    @Singular 어노테이션을 사용하면 리스트 같은 컬렉션 객체를 빌더 패턴으로 다룰 때 리스트 객체 자체를 넘기는게 아니라 해당 리스트에 요소를 추가하는 방식으로 생성할 수 있다. (즉 값을 하나 하나 메서드로 만들어 넘길 수 있다.)
@Builder
@ToString
public class Member {
    private String name;
    private String id;
    private String pwd;
    @Singular private List<String> hobbies;
}
Member member = Member.builder()
                .name("name")
                .id("id")
                .pwd("pwd")
                // 값을 메서드로 하나 하나씩 넘긴다.
                .hobby("운동")
                .hobby("독서")
                .hobby("잠")
                .build();

        System.out.println(member);
 // 출력 결과: Member(name=name, id=id, pwd=pwd, hobbies=[운동, 독서, 잠])

상속 관계 빌더 사용 방법

상속 관계에서 빌더 패턴을 사용할 때는 부모 자식 클래스에 @SuperBuilder 어노테이션을 사용하면 된다.

결론

setter 메서드를 지양하고 setter 메서드 대신 @Builder 어노테이션을 지향하자

profile
더 좋은 개발자가 되기위한 과정

0개의 댓글