본문 바로가기

JAVA

Java - 빌더 패턴(Builder Pattern)

빌더 패턴(Builder Pattern)이란?

: GoF(Gang of Four) 디자인 패턴 중 생성패턴(Creational)에 해당하며, 빌더패턴은 복잡한 객체를 생성하는 클래스와 표현하는 클래스를 분리하여 동일한 절차에서도 서로 다른 표현을 생성하는 방법을 제공한다. 자바에서는 생성자에 값을 담아 보낼때, 어떤 값을 전달하는지 알기가 힘들며, 또 인자가 많아지면 더더욱 확인이 어려워진다.

 

- GoF 디자인패턴 더 알아보기: https://velog.io/@namezin/GoF-design-pattern

 

점증적 생성자 패턴(telescoping construtor patter)

: 클래스 내에 오버로딩을 통해 생성자를 여러개 작성하는 것

= 장점

    - 선택적으로 인자를 받을 수 있다.

= 단점

    - 인자가 추가되는 상황이 발생한다면, 유지보수가 어렵다.

    - 코드 가독성이 떨어진다. 생성자에 들어가는 데이터가 무슨 데이터인지 확인이 어려움 (IDE에서 param명이 무엇인지 보여주는 기능으로 어느정도 극복은 가능하지만..)

 

class Car {
    private String carNo;
    private String carName;
    private String companyName;
    private int displacementVolume;
    private String issueDate;

    // ....
    // ....
    // ....

    public Car(String carNo, String carName, String companyName, int displacementVolume) {
        this.carNo = carNo;
        this.carName = carName;
        this.companyName = companyName;
        this.displacementVolume = displacementVolume;
    }

    public Car(String carNo, String carName, String companyName, int displacementVolume, String issueDate) {
        this.carNo = carNo;
        this.carName = carName;
        this.companyName = companyName;
        this.displacementVolume = displacementVolume;
        this.issueDate = issueDate;
    }
}

 

자바 빈 패턴(Java Bean Pattern)

: 자바 빈객체를 만들때 기본적으로 사용하는 패턴이다.

= 장점

    - 인자의 의미를 파악하기가 쉽다. (물론 필드명을 잘 지어야하겠죠..?)

    - 복잡하게 여러 개의 생성자를 만들 필요가 없다.

= 단점

    - 객체의 일관성이 깨짐

    - setter 메소드의 존재로, 불변성의 확보가 어렵다.

public static void main(String[] args) {
    Car car = new Car();
    car.setCarNo("12차3456");
    car.setCarName("코나2020");
    car.setCompanyName("현대");
    car.setDisplacementVolume("1591");
    car.setIssueDate("2020-04-09");
}

class Car {
    private String carNo;
    private String carName;
    private String companyName;
    private int displacementVolume;
    private String issueDate;

    public String getCarNo() {
        return carNo;
    }

    public void setCarNo(String carNo) {
        this.carNo = carNo;
    }

    public String getCarName() {
        return carName;
    }

    public void setCarName(String carName) {
        this.carName = carName;
    }

    public String getCompanyName() {
        return companyName;
    }

    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }

    public int getDisplacementVolume() {
        return displacementVolume;
    }

    public void setDisplacementVolume(int displacementVolume) {
        this.displacementVolume = displacementVolume;
    }

    public String getIssueDate() {
        return issueDate;
    }

    public void setIssueDate(LocalDate issueDate) {
        this.issueDate = issueDate;
    }
}

점증적 생성자 패턴자바 빈 패턴의 장점을 결합한 것이 빌더 패턴이다.

 

클라이언트 코드에서 필요한 객체를 직접 생성하는 대신, 그 전에 필수 인자들을 전달하여 빌더 객체를 만든 뒤, 빌더 객체에 정의된 설정 메서드들을 호출하여 인스턴스를 생성한다.

 

빌더 패턴 사용 예제

public static void main(String[] args) {
    // 빌더패턴 사용
    Car car = new Car.Builder("12차3456")
        .carName("코나")
        .companyName("현대")
        .displacementVolume("1591")
        .build();
}

public class Car {
    private String carNo;
    private String carName;
    private String companyName;
    private int displacementVolume;
    private String issueDate;

    // 외부에서는 접근할 수 없고, Builder 클래스로 사용가능하도록함
    private Car(Builder builder) {
        this.carNo = builder.carNo;
        this.carName = builder.carName;
        this.companyName = builder.companyName;
        this.displacementVolume = builder.displacementVolume;
        this.issueDate = builder.issueDate;
    }

    public static class Builder { // 외부에서 Car.Builder() 형태로 접근 가능하게 static 사용
        String carNo;
        String carName;
        String companyName;
        int displacementVolume;
        String issueDate;

        public Builder(String carNo) {
            this.carNo = carNo;
        }

        public Builder carName(String carName) {
            this.carName = carName;
            return this;
        }

        public Builder companyName(String companyName) {
            this.companyName = companyName;
            return this;
        }
        public Builder displacementVolume(int displacementVolume) {
            this.displacementVolume = displacementVolume;
            return this;
        }

        public Builder issueDate(String issueDate) {
            this.issueDate = issueDate;
            return this;
        }

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

위의 작업대신, 

Lombok의 @Builder 어노테이션으로 편하게 사용할 수도 있다.

public static void main(String[] args) {
    // 빌더패턴 사용
    Car car = new Car.Builder("12차3456")
        .carName("코나")
        .companyName("현대")
        .displacementVolume("1591")
        .build();
}

@Builder
public class Car {
    private String carNo;
    private String carName;
    private String companyName;
    private int displacementVolume;
    private String issueDate;
}

 

 

참고자료

- https://velog.io/@namezin/%EB%B9%8C%EB%8D%94Builder

- https://gonyda.tistory.com/9