본문 바로가기
Develop/Design

[Design Pattern] 빌더 패턴 정리

by 코딩의성지 2022. 9. 27.

빌더패턴은 디자인 패턴 중 생성 패턴 중 하나이다.

 

빌더는 복잡한 Object들을 단계별로 구축할 수 있게 해준다. 이 패턴을 활용하면 동일한 구성코드를 통해 다양한 타입과 표현을 제공받을 수 있다. 쉽게말해서 이 패턴을 이용해 우리는 객체를 편리하게 만들어 낼 수 있다.

 

기존에 우리는 빌더 패턴없이 setter 메서드를 활용하거나 생성자를 이용해 객체를 생성해왔다.

 

아래는 setter 를 이용한 객체생성의 예시이다.

 

setter

public class Person {
    private String name;
    private int age;

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
Person person = new Person();
person.setName("kang");
person.setAge(33);

setter를 이용해 객체를 생성하면 아주 큰 단점들이 존재한다. 

setter는 필수적인 멤버변수를 빠트릴 우려가 존재한다. 필수적인 멤버변수를 하나라도 빠트리면 객체가 미완성된 채로 어플리케이션에서 사용이 된다. 이 객체는 실행시점에는 문제가 없다. 이게 더 문제다. 겉으로는 문제가 없어보이지만 잘못만들어진 이 객체 때문에 객체지향 설계의 품질이 저하되고 나아가 심각한 시스템 에러를 초래할 수도 있다. 이팩티브 자바라는 책에서는 이를 "일관성이 무너진 상태" 라고 표현한다.

 

그리고 setter는 public 으로 제공되기 대문에, 누구나 접근이 가능하다. 이는 정보의 일관성을 지키기가 어려워진다. setter로는 final 키워드를 이용해 불변객체로 만들어 낼수도 없다.

 

마지막으로 setter를 사용하면 의도를 알기가 어려워진다. 이 setter가 변경을 위해 사용된건지, 초기화를 위해 사용된건지 코드 전체를 보지 않는 한 사용의도를 한눈에 파악하기 어렵다.

그래서 특정의도에 따라 변경이 일어나는 메서드는 setter를 사용하지 않고 메서드명 자체를 명확하게 해주는 편이 좋다.또한 생성의 의도로 setter를 사용하는 것은 지양하고, 변경이 되지 않을 필드는 과감하게 setter 메서드를 삭제해 주도록하자.

(setter 류의 변경성 메서드는 필요할때만 만들어 쓰라는 얘기다.)

 

다음은 생성자를 이용해 객체를 생성하는 방법이다.

 

생성자

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
Person person = new Person("kang", 33);

생성자를 사용하면 하나의 생성자 메서드로 완성된 객체를 반환함으로써 일관성 있는 코드를 작성할 수 있다는 장점이 있다. 하지만 이 생성자도 단점이 존재한다.

 

일단 필드에서 필요하지 않은 부분은 null 값으로 채워줘야한다는 크리티컬한 단점이 있다. 물론 여러개의 생성자를 만들어주는 방법도 있지만 이러한 경우 코드량이 늘어나고, 오버로딩 기본원칙에 걸려 필요한 생성자를 못만드는 경우도 생긴다. 

그리고 파라미터가 많다보면 어디에 어떤 파라미터가 들어가는지 관리하기가 쉽지가 않다. (물론 요즘 좋은 개발 툴들은 자동으로 어디에 어떤게 들어가야하는지를 친절하게 알려준다.)

 

이렇게 파라미터가 너무 많거나할때 빌더 패턴은 큰 효과를 발휘한다.

 

빌더패턴을 사용하면 클래스 자체의 코드는 길어진다는 단점은  있지만, 객체지향 세계에서 가장 중요한 것은 객체이기 때문에 클래스가 길어지는 한이 있떠라도 객체 생성을 더 편하게 하고 일관성 있게 만들어내는 것이 더 중요하다.

 

그러니 빌더패턴을 적극적으로 활용하자.

아래는 빌더패턴의 예시이다.

 

빌더패턴

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    static public class Builder {
        private String name;
        private int age;

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

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

        public Person build() {
            return new Person(name, age);
        }
    }

}
Person person = new Person.Builder()
                       .age(33)
                       .name("kang")
                       .build();

 

마지막으로 빌더패턴의 장점을 정리하고 마무리하겠다.

첫째, 빌더패턴을 활용하면 코드의 가독성이 높아지고, 사용의 의도를 명확하게 알고 사용할 수가 있다.

둘째, 필요한 값만 설정하면 직접 null을 넣는 번거로움을 겪을 필요도 없이 나머지 값을 null로 채울 수 있다.

셋째, 생성자를 사용하는 것처럼 일관성을 지킬 수 있다. 체인처럼 연결해서 하나의 메서드 처럼 사용하고, 마지막에 bulid() 꼭 호출해줘야하기에 일관성이지켜즤는 것이다.

 

빌더패턴이 이토록 유용하니 꼭 다음 프로젝트하실때 써보길 바란다.

 

즐코딩 ~

반응형

댓글