본문 바로가기
Java

객체 생성 패턴 - Builder Pattern

by Eric_K 2022. 2. 20.

객체를 생성할 때 많이 사용되는 방법에는 생성자 패턴, Setter를 이용한 자바빈즈 패턴 등이 있다.

이 방법들과 Builder 패턴을 이용한 객체 생성에는 무슨차이가 있는지 알아보자.

 

Builder 패턴을 이용한 객체 생성의 장점

   1. 메소드 체이닝 방식으로 원하는 값만 세팅하기가 편하다.

   2. 필드값이 추가되었을 때 최소한의 소스 수정으로 유연하게 대처할 수 있다.

   3. 불변성을 확보할 수 있다.

   4. 가독성을 높일 수 있다.

 

1. 메소드 체이닝 방식으로 원하는 값만 세팅하기가 편하다.

가령 아래와 같은 필드를 가지고 있는 Dog 객체를 'note' 필드는 빈값으로 둔 채 생성자 패턴으로 인스턴스화 시키려고 했을 때, 빈 값이라도 넣어주거나 'note'를 파라미터로 가지지 않는 새로운 생성자를 오버로딩 해야한다.

 

Dog 객체

 

 

Dog dog = new Dog("몽이",9,"말티즈","");

 

하지만 Builder 패턴을 이용하면 아래와 같이 원하는 필드만 편하게 세팅할 수 있다.

Dog dog = new Dog.DogBuilder().name("몽이")
                              .age(9)
                              .breed("말티즈")
                              .build();

 

 

2. 필드값이 추가되었을 때 최소한의 소스 수정으로 유연하게 대처할 수 있다.

위 예시 객체에서 'character' 라는 필드가 추가되었을 때, 생성자 패턴은 기존 생성자 파라미터에 추가하거나 새로운 생성자를 오버로딩 해야한다. 전자의 경우 해당 객체를 사용하는 곳이 많다면 일일히 파라미터를 추가해줘야하는 번거로움이 있고, 후자의 경우에는 그나마 소요가 덜하겠지만, 생성자를 추가로 만들어줘야 한다.

 

Builder 패턴을 사용하면 객체에 필드만 추가하고 해당 필드를 사용해야하는 부분에만 값을 세팅하도록 하면 되기 때문에 좀 더 유연하게 대처할 수 있다.

 

3. 불변성을 확보할 수 있다.

Setter를 구현하는 자바빈즈 패턴은 객체의 필드 값이 설정된 이후에 다른 값으로 변경될 수 있다. 이렇게 변경 가능성을 열어두면 예상치 못한 부분에서 값이 바뀔 수 있고, 어디서 값이 바뀌었는지 파악하기가 어렵다. 이는 유지보수성을 크게 떨어트린다. Builder 패턴의 경우는 Setter를 구현하지 않기 때문에 불변성을 확보할 수 있다. 불변성이 왜 중요한 지에 대해서 잘 정리한 글은 여기를 참고하면 좋다.

 

[Java] 불변 객체(Immutable Object) 및 final을 사용해야 하는 이유

클린코드를 읽어도, 이펙티브 자바를 읽어도, 개발을 잘하는 팀의 얘기를 들어도 항상 좋은 코드를 얘기할 때면 불변의 객체를 필연적으로 접하게 되는 것 같습니다. 그래서 이번에는 불변의 객

mangkyu.tistory.com

 

4. 가독성을 확보할 수 있다.

생성자를 이용한 객체생성은 생성자의 파라미터 순서대로 값을 넣을 뿐, 인스턴스화를 하는 부분의 소스만 봐서는 해당 값이 어느 필드에 할당되는지 직관적으로 알 수 없다.

 

Dog dog = new Dog("몽이",9,"말티즈",""); // 각 값이 어느 필드로??

반면 Builder 패턴을 이용하면 값을 할당하는 메소드 명을 보고 어느 값인지 알 수 있다.

 

Dog dog = new Dog.DogBuilder().name("몽이") // name : 이름
                              .age(9) // age : 나이
                              .breed("말티즈") // breed : 품종
                              .build();

 

 

Builder 패턴 사용시 유의할 점

Builder 패턴은 내부적으로 아래와 같이 static Builder를 만들어주어야 한다. 이렇게 되면 static 영역을 잡아먹게 되는데 하드웨어가 고도로 발전한 오늘날 성능에 크게 영향을 줄 확률은 적지만 인지는 하고 있어야 한다.

 

public class Dog {
    private final String name;
    private final int age;
    private final String breed;
    private final String note;


    public Dog(DogBuilder dogBuilder){
        this.name = dogBuilder.name;
        this.age = dogBuilder.age;
        this.breed = dogBuilder.breed;
        this.note = dogBuilder.note;
    }

    public static class DogBuilder {
        private String name;
        private int age;
        private String breed;
        private String note;


        public DogBuilder name(String name) {
            this.name = name;
            return this;
        }

        public DogBuilder age(int age) {
            this.age = age;
            return this;
        }

        public DogBuilder breed(String breed) {
            this.breed = breed;
            return this;
        }

        public DogBuilder note(String note) {
            this.note = note;
            return this;
        }

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

Builder 패턴에 대해서는 여기를 참고하면 좋다.

 

GitHub - iluwatar/java-design-patterns: Design patterns implemented in Java

Design patterns implemented in Java. Contribute to iluwatar/java-design-patterns development by creating an account on GitHub.

github.com

 

 

 

 

댓글