[Java] 객체를 생성하는 대표적인 패턴, 빌더패턴

wakeup Lee·2023년 3월 19일
0

자바

목록 보기
3/6
post-thumbnail

객체를 생성하는 방법에는 생성자, 정적 팩토리 메서드, 빌더패턴이 대표적이다.
하지만 생성자와 정적 팩토리 메서드에 치명적인 단점이 존재하는데, 선택적 매개변수가 많은 경우 적절한 대응이 어렵다는 점이다. 이러한 문제를 해결할 수 있는 방법이 빌더패턴이다.

빌더패턴을 설명하기에 앞서 위의 단점을 보완할 수 있는 두 가지 패턴을 먼저 소개한다.

1. 점층적 생성자 패턴

점층정 생성자 패턴은 필수 매개변수를 생성자부터 선택 매개변수 1개를 받는 생성자, 2개를 받는 생성자 형태로 점차적으로 매개변수를 늘려가는 방식이다.

다음은 점층적 생성자 패턴을 활용한 생성자 생성 방법이다.

public class Pizza {

    private String dough = ""; // 필수
    private String cheese = ""; // 필수
    private String ham = ""; // 선택
    private String onion = ""; // 선택
    private String mushroom = ""; //선택

    public Pizza(String dough, String cheese) {
        this(dough, cheese, "");
    }

    public Pizza(String dough, String cheese, String ham) {
        this(dough, cheese, ham, "");
    }

    public Pizza(String dough, String cheese, String ham, String onion) {
        this(dough, cheese, ham, onion, "");
    }

    public Pizza(String dough, String cheese, String ham, String onion, String mushroom) {
        this.dough = dough;
        this.cheese = cheese;
        this.ham = ham;
        this.onion = onion;
        this.mushroom = mushroom;
    }
}
Pizza pizza = new Pizza("밀가루반죽 도우", "모짜렐라 치즈", "", "양파");

위의 코드처럼 생성자를 생성하게 되면 매개변수의 수가 많을 경우 코드를 작성하거나 읽기 어려울 수 있다. 매개변수의 각 의미를 헷갈릴 수 있고, 매개변수가 몇 개인지도 주의 깊게 세어야 할 수도 있다. 매개변수의 위치를 헷갈려 원하는 값을 얻지 못할 수도 있다.
이러한 점층적 생서자 패턴의 단점을 보완한 방법이 자바빈즈 패턴이다.

2. 자바빈즈 패턴

점층적 생성자 패턴을 보완한 패턴으로 매개변수가 많을 때 활용할 수 있다. 이 패턴은 매개변수가 없는 생성자로 객체를 만든 후, 세터 메서드들을 호출해 원하는 매개변수의 값을 설정하는 방식으로 사용한다.

다음은 자바빈즈 패턴을 활용한 생성자 방법이다.

public class Pizza {

    private String dough = ""; // 필수
    private String cheese = ""; // 필수
    private String ham = ""; // 선택
    private String onion = ""; // 선택
    private String mushroom = ""; //선택

    public Pizza() {
    }

    public void setDough(String dough) {
        this.dough = dough;
    }

    public void setCheese(String cheese) {
        this.cheese = cheese;
    }

    public void setHam(String ham) {
        this.ham = ham;
    }

    public void setOnion(String onion) {
        this.onion = onion;
    }

    public void setMushroom(String mushroom) {
        this.mushroom = mushroom;
    }		
}
Pizza pizza = new Pizza();
pizza.setDough("밀가루반죽 도우");
pizza.setCheese("모짜렐라 치즈");
pizza.setHam("스팸");
pizza.setOnion("양파");
pizza.setMushroom("양송이버섯");

자바빈즈 패턴의 단점은 매개변수가 많아지면 여러 메서드를 호출해야 하고, 객체가 완전히 생성되기 전까지는 일관성이 무너진 상태에 놓인다. 이러한 자바빈즈 패턴의 단점을 보완한 방법이 바로 빌더패턴이다.

3. 빌더패턴

위의 점층적 생성자 패턴의 안전성과 자바빈즈 패턴의 가독성을 겸비한 패턴을 합친 패턴으로 필수 매개변수만으로 생성자를 호출하여 객체를 얻고, 세터 메서드들로 선택 매개변수들을 설정한다. 최종적으로 매개변수가 없는 build 메서드를 호출하여 필요한 객체를 얻는다.

다음은 빌더패턴을 활용한 생성자 방법이다.

public class Pizza {

    private String dough = "";
    private String cheese = "";
    private String ham = "";
    private String onion = "";
    private String mushroom = "";

    public static class Builder {

        private String dough = "";
        private String cheese = "";

        private String ham = "";
        private String onion = "";
        private String mushroom = "";

        public Builder(String dough, String cheese) {
            this.dough = dough;
            this.cheese = cheese;
        }

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

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

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

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

    private Pizza(Builder builder) {
        this.dough = builder.dough;
        this.cheese = builder.cheese;
        this.ham = builder.ham;
        this.onion = builder.onion;
        this.mushroom = builder.mushroom;
    }
}
Pizza pizza = new Pizza.Builder("밀가루반죽 도우", "모짜렐라 치즈")
        .setHam("스팸").setOnion("양파").setMushroom("양송이버섯").build();

빌더는 보통 정적 멤버 클래스로 만들고, 세터 메서드들은 빌더 자신을 반환하기 때문에 연쇄적으로 호출을 할 수 있도록 자기 자신을 반환한다.

[참고자료]
이펙티브 자바

profile
백엔드 개발자

0개의 댓글