Clean Code

[Design Pattern] 생성 패턴 - 빌더 패턴

yaini 2022. 3. 1. 14:07
반응형

 

생성(construction)과 표기를 분리해 복잡한 객체를 생성한다.

별도의 Builder 클래스를 만들어 필수 값에 대해서는 생성자를, 선택적인 값에 대해서는 메소드를 통해 값을 입력 받은 후, build 메소드를 통해 하나의 인스턴스 리턴

  • 선택적인(Optional) 멤버 변수, 파라미터나 지속성 없는 상태 값이 많을 때
  • 팩토리 패턴에서 생성해야 하는 하위 클래스들이 복잡할 때

단점

  • 매개변수가 적은 경우 생성자보다 코드가 장황해 진다.

구현 방법

  • 빌더 클래스를 Static Nested Class로 생성
    • nested class: 클래스 내부 클래스
public static class WalletBuilder {
	// Required
	private final int cash;

	// Optional
	private int creditCard;
	private boolean identificationCard;
}
  • 생성자는 public, 필수 값들에 대해 생성자의 파라미터로 받는다.
public WalletBuilder(int cash) { // Required
	this.cash = cash;
}
  • 선택적인(Optional)한 값들에 대해서 속성마다 메소드로 제공, 메소드의 리턴 값은 빌더 객체 자신
public WalletBuilder creditCard(int creditCard) { // Optional
	this.creditCard = creditCard;
	return this;
}
  • 빌더 클래스 내에 build() 메소드를 정의하여 인스턴스를 리턴한다. build() 를 통해서만 객체를 생성하기 때문에 클래스의 생성자는 private으로 정의한다.
public Wallet build() { // build method
	return new Wallet(this);
}

private Wallet(WalletBuilder builder) { // constructor
	this.cash = builder.cash;
	this.creditCard = builder.creditCard;
	this.identificationCard = builder.identificationCard;
}

전체 코드

public class Builder {
    public static void main(String[] args){
        Wallet myWallet = new Wallet.WalletBuilder(1000)
                .identificationCard(true)
                .creditCard(200)
                .build();
    }
}

class Wallet {
    private final int cash;
    private int creditCard;
    private boolean identificationCard;

    private Wallet(WalletBuilder builder) {
        this.cash = builder.cash;
        this.creditCard = builder.creditCard;
        this.identificationCard = builder.identificationCard;
    }

    public static class WalletBuilder {
        // Required
        private final int cash;

        // Optional
        private int creditCard;
        private boolean identificationCard;

        public WalletBuilder(int cash) {
            this.cash = cash;
        }

        public WalletBuilder creditCard(int creditCard) {
            this.creditCard = creditCard;
            return this;
        }

        public WalletBuilder identificationCard(boolean identificationCard) {
            this.identificationCard = identificationCard;
            return this;
        }

        public Wallet build() {
            return new Wallet(this);
        }
    }

}

 

자바 빈즈 패턴

빌더 패턴과 달리 생성자로 객체를 생성한 후 Setter Method를 호출하여 매개변수의 값을 설정하는 패턴

설정 해야 할 매개 변수 만큼 Setter 메소드를 호출해며 불변 객체를 생성할 수 없다.

Wallet myWallet = new Wallet();

myWallet.setCash(1000);
myWallet.setIdentificationCard(true);
myWallet.setCreditCard(200);

 

자바 API Builder 패턴

java.lang.StringBuilder#append() (unsynchronized)
java.lang.StringBuffer#append() (synchronized)
java.nio.ByteBuffer#put() (also on CharBuffer, ShortBuffer, IntBuffer, LongBuffer, FloatBuffer and DoubleBuffer)
javax.swing.GroupLayout.Group#addComponent()
All implementations of java.lang.Appendable
java.util.stream.Stream.Builder

 

 

최근엔 롬복의 @Builder 어노테이션으로 인해 코드를 추가적으로 작성해야 하는 경우가 줄어들었다.

하지만 Builder를 커스터마이징 하거나 직접 작성할 때 코드가 장황해지는 단점이 있다.

매개변수가 적은 경우 생성자가 더 가독성이 좋기 때문에 Builder를 무조건 쓰지 않을때도 많았다.

그럼에도 불구하고 매개변수가 많은 객체를 생성할 때 굉장히 좋은 패턴

 

 

참고

https://devfunny.tistory.com/337
https://velog.io/@ha0kim/Design-Pattern-생성-패턴Creational-Patterns
https://ko.wikipedia.org/wiki/디자인_패턴_(책)
https://stackoverflow.com/questions/1673841/examples-of-gof-design-patterns-in-javas-core-libraries/2707195#2707195

 

 

https://ko.wikipedia.org/wiki/디자인_패턴_(책) https://velog.io/@ha0kim/Design-Pattern-생성-패턴Creational-Patterns 

반응형