오늘 공부한 내용

  • 코드카타 2문제
  • Spring 심화 프로젝트 작성

 

새로 알게된점

@Builder

빌더 패턴 (Builder patter) 이란?

 

복잡한 Object들을 단계별로 구축할 수 있는 생성 디자인 패턴을 말하며 이 패턴을 사용하면, 동일한 구성코드를 사용하여 다양한 타입과 표현을 제공한다.

 

일반적으로 객체를 정의하고 그 객체를 생성할 때 보통 생성자를 통해 생성하는 것을 생각한다.

Bag bag = new Bag("name", 1000, "memo");

 

 

하지만 생성자를 통해 객체를 생성하는데 몇 가지 단점이 있기에 빌더패턴으로 작성시 이를 보완할수 있다.

Bag bag = Bag.builder()
		.name("name")
        	.money(1000)
        	.memo("memo")
        	.build();

 

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

 

빌더를 사용하는 이유

  •  뛰어난 가독성을 가지고 있다.

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

예시로 위에 작성했던 생성자 파라미터가 3개가 아닌 7~8개가 되면 어떻게 될까?

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();

 

  •  데이터의 순서에 상관없이 객체 성성이 가능하다.

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

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();

 

추가적인 장점으로

  • 불필요한 생성자의 제거
  • setter 메서드가 없으므로 변경 불가능한 객체를 만들수 있다. (객체불변성)
  • 한번에 객체를 생성하므로 객체 일관성이 깨지지 않는다.

 

빌더는 사용하는 방법으로 다음과 같이 만들어진다.

- Member 클래스 내부에 빌더클래스 생성.

- 각 멤버 변수별 메서드를 작성, 각 메소드는 변수에 값을 set하고 빌더객체를 리턴한다.

- build() 메서드는 필수 멤버변수의 null체크를 하고 지금까지 set된 builder를 바탕으로 Member 클래스의 생성자를 호출하고 인스턴스를 리턴.

public class Member {

    private String nickname; //필수
    private String password; //필수
    private Gender gender; //선택

    public static class Builder {
        private final String nickname;
        private final String password;
        private Gender gender;

        // 필수변수는 생성자로 값을 넣는다.
        public Builder(String nickname, String password) {
            this.nickname = nickname;
            this.password = password;
        }

        // 멤버변수별 메소드: 빌더클래스의 필드값을 set하고 빌더객체를 리턴한다.
        public Builder gender(Gender gender) {
            this.gender = gender;
            return this;
        }

        // 빌더메소드
        public Member build() {
            return new Member(this);
        }
    }

    public Member(Builder builder) {
        this.nickname = builder.nickname;
        this.password = builder.password;
        this.gender = builder.gender;
    }
}

Member memberEntity = new Builder("minji", "1234")
                .gender(Gender.F)
                .build();

하지만 빌더 패턴도 역시 단점이 존재한다. 객체를 생성하려면 우선 빌더객체를 생성해야 하고, 보다시피 다른 패턴들보다 많은 코드를 요구하기 때문에 인자가 충분히 많은 상황에서 이용할 필요가 있다.

 

아니면 @Builder 을 이용하여 빌더클래스를 직접 만들지 않고 어노테이션 하나로 클래스를 생성할 수 있다.

클래스 또는 생성자 위에 @Builder 어노테이션을 붙여주면 빌더패턴 코드가 빌드된다.

생성자 상단에 선언시 생성자에 포함된 필드만 빌더에 포함된다.

  • 클래스 전체 Builder 적용
@Getter @Builder // ✨ 클래스 전체 필드를 빌더로 사용 가능!
public class UserLombok {

  private Long id;
  private String email;
  private String password;
  private String name;
}

// 사용예제
public User join(String email, String password, String name) {
  UserLombok build = UserLombok.builder()
            .email(email)
            .password(password)
            .name(name)
            .build();
  ...
}
 
 
  • 특정 생성자에서만 Builder 적용 가능
@Getter
public class UserLombok {

  private Long id;
  private String email;
  private String password;
  private String name;
  
  public UserLombok(Long id, String email, String password, String name) {
    this.id = id;
    this.email = email;
    this.password = password;
    this.name = name;
  }

  @Builder // ✨ 빌더는 email, password만 사용 가능
  public UserLombok(String email, String password) {
    this.email = email;
    this.password = password;
  }
}

// 사용예제 - email, password만 가능!
public User join(String email, String password, String name) {
  UserLombok build = UserLombok.builder()
            .email(email)
            .password(password)
            .build();
  ...
}
 

 

 

+ Recent posts