Design Pattern - Builder Pattern

Stella·2022년 4월 19일
0

Java

목록 보기
5/18

Builder Pattern

  • 객체 생성 시 많이 사용되는 패턴.

장점

  1. 필요한 데이터만 설정 가능.
  2. 유연성 확보.
  3. 코드의 가독성 높임.
  4. 변경 가능성 최소화.
User user = User.build()
			.id("aaa")
            .name("aaa")
            .password("password")
            .build()

Effecive Java의 builder pattern

  • 객체 생성 깔끔
    • Telescoping constructor pattern (점층적 생성자 패턴)
    • JavaBeans pattern (자바빈 패턴) -> 점층적 생성자 패턴의 대안
    • builder pattern (빌더 패턴) -> JavaBeans 패턴의 대안
  • 객체 생성 유연
    • builder interface를 이용하여 다양한 builder 사용.

Telescoping constructor pattern (점층적 생성자 패턴)

  1. 필수 생성자(필수 인자를 받음) 생성.
  2. 1개의 선택적 인자를 받는 생성자 추가.
  3. 2개의 선택적 인자를 받는 생성자 추가.
  4. 반복
  5. 모든 선택적 인자를 받는 생성자 추가.
public class Employee {

	private final String name;  // 필수 인자
    private final String salary; // 선택적 인자
    private final String email;  // 선택적 인자
    
    // 필수 인자를 받는 생성자 
    public Employee(String name){
    	this(name,"연봉 비공개", "이메일 비공개");
        }
    
    // 1개의 선택적 인자를 받는 생성자
    public Employee(String name, String salary){
    	this(name,salary,"이메일 비공개");
    }
    // 모든 인자를 다 받는 생성자
     public Employee(String name, String salary, String email){
    	this.name = name;
        this.salary = salary;
        this.email = email;
        } 

장점

  • 입력되는 Parameter에 맞는 생성자 사용 가능.

단점

  • 다른 생성자를 호출하는 생성자가 많으므로, 인자가 추가되면 코드 수정 어려움.
  • 코드 가독성이 떨어짐.
    • parameter의 의미를 알기 어려움.
// parameter가 무엇을 의미하는지 파악하기 어려움.
Order newOrder = new Order(1,200, 5000, 1,2);

JavaBeans Pattern

  • setter를 사용해서 코드를 읽기 좋게 만듬.
Order newOrder = new Order();
newOrder.setId(1);
newOrder.setQuentity(200);
newOrder.setPrice(5000);
newOrder.setProduct(1);
newOrder.setStore(2);

장점

  • parameter 파악이 쉬워짐.
  • 여러 생성자 불필요.

단점

  • 객체의 일관성이 없음.
    • 1회의 호출로 객체 생성이 끝나지 않음. 한번에 생성되지 않고, 생성된 객체에 값을 추가하고 추가함.
  • setter가 있으면 변경불가능 클래스 만들 수 없음.

Builder Pattern(Effective Java 스타일)

public class Product {
	private final String name;
    private final int quentity;
    private final int price;
    private final String store;
    private final String option;
    
    public static class Builder {
    // Required parameters(필수 인자)
    private final String name;
    private fianl int quentity;
    private final int price;
    
    // Optional Parameters - initialized to default values
    private String store = "None";
    private String option = "None";
    
    public Builder(String name, int quentity, int price){
    	this.name = name;
        this.quentity = quentity;
        this.price = price;
    }
    public Builder store(String store){
    	store = store;
        return this; // 이렇게하면 .으로 체인을 이어갈 수 있음.
    }
    public Builder option(String option){
    	option = option;
        return this;
    }
    
    public Product build() {
    	return new Product(this);
    }
  }
  
  private Product(Builder builder){
  		name = builder.name;
        quentity = builder.quentity;
        price = builder.price;
        store = builder.store;
        option = builder.option;
   }
   }

객체생성 1

Product.bbuilder builder = new Product.builder('chip', 100, 2000);
builder.store('market');
builder.option('crispy');
Product prod = budiler.build();

객체생성 2

Product prod = new Product.Builder('chip', 100, 2000)
						      .store('market')
                              .option('crispy')
                              .build(); // build()가 객체 생성해서 return

장점

  • parameter의 의미 알기 쉬움.
  • setter가 없어서 변경 불가능 객체 만들 수 있음.
  • 한 번에 객체 생성 가능 -> 객체 일관성이 깨지지 않음.
  • build() 함수가 잘못된 값이 입력되었는지 검증 가능.

Lombok의 @Builder

  • Class나 constructor에 @Builder annotation을 붙여주면 이펙티브 자바와 비슷한 빌더 패턴 가능.

Class에 @Builder

@Builder
public class Product {
	private final String name;
    private final int quentity;
    private final int price;
    private final String store;
    private final String option;
    }

Constructor에 @Builder

public class Product {
	private final String name;
    private final int quentity;
    private final int price;
    private final String store;
    private final String option;
    }
@Builder
 private Product(String name, int quentity, int price, String store, String option){
  		this.name = name;
        this.quentity = quentity;
        this.price = price;
        this.store = store;
        this.option = option;

객체 생성 1

Product.ProductBuilder builder = Product.builder();
builder.name('chip');
builder.quentity(100);
Product prod = builder.build();

객체 생성 2

Product prod = Product.builder()
					  .name('chip')
                      .quentity(100)
                      .build();

클래스 선언부에 @Builder 사용 금지

  • @Builder를 class에 달아주면 @AllArgsConstructor도 같이 달아주는 것과 같음. 가급적 직접 만든 생성자에 달아주기.

Builder Interface

  • Interface를 만든 후 builder class에서 implements해서 사용.
public interface Builder<T> {
	public T build();
}

Ref:
https://johngrib.github.io/wiki/pattern/builder/
https://mangkyu.tistory.com/163

profile
Hello!

0개의 댓글