관리 메뉴

나만을 위한 블로그

빌더(Builder) 패턴이란? 본문

개인 공부/디자인 패턴

빌더(Builder) 패턴이란?

참깨빵위에참깨빵_ 2022. 1. 2. 23:20
728x90
반응형

안드로이드 앱 개발을 하다보면 AlertDialog라는 알림창을 못해도 한 번은 쓰게 된다.

이 때 AlertDialog 안에서 보여줄 제목, 메시지, 각 버튼들을 설정할 때 아래처럼 메서드 체이닝 형태로 쓸 수 있다.

 

 

그리고 메서드 체이닝을 하기 전에 컨텍스트를 생성자로 넘겨 AlertDialog.Builder 객체를 만들어야 한다.

이 Builder란 키워드가 붙은 이유는 AlertDialog가 빌더 패턴으로 만들어졌기 때문이다. 빌더의 사전적 정의는 아래와 같다.

 

건축업자, 건축 회사, ~을 만드는(개발하는) 사람(것)

 

이 빌더 패턴에 대해 위키백과는 아래와 같이 말한다.

 

https://ko.wikipedia.org/wiki/%EB%B9%8C%EB%8D%94_%ED%8C%A8%ED%84%B4

 

빌더 패턴 - 위키백과, 우리 모두의 백과사전

빌더 패턴이란 복합 객체의 생성 과정과 표현 방법을 분리하여 동일한 생성 절차에서 서로 다른 표현 결과를 만들 수 있게 하는 패턴이다. 2 단어 요약 : 생성자 오버로딩 /** "Product" */ class Pizza {

ko.wikipedia.org

빌더 패턴이란 복합 객체의 생성 과정과 표현 방법을 분리해 동일한 생성 절차에서 서로 다른 표현 결과를 만들 수 있게 하는 패턴이다. 2단어 요약 : 생성자 오버로딩

 

https://en.wikipedia.org/wiki/Builder_pattern

 

Builder pattern - Wikipedia

From Wikipedia, the free encyclopedia Jump to navigation Jump to search The builder pattern is a design pattern designed to provide a flexible solution to various object creation problems in object-oriented programming. The intent of the Builder design pat

en.wikipedia.org

빌더 패턴은 객체지향 프로그래밍에서 다양한 객체 생성 문제에 대한 유연한 솔루션을 제공하기 위해 설계된 GoF 디자인 패턴 중 하나다. 빌더 패턴의 목적은 복잡한 객체의 구성을 해당 표현과 분리하는 것이다. 빌더 패턴은 다음과 같은 문제를 해결한다

- 별도의 Builder 객체에서 복잡한 객체의 일부를 만들고 조합하는 걸 캡슐화한다
- 클래스는 객체를 직접 생성하는 대신 Builder 객체에 객체 생성을 위임한다

클래스 안에서 직접 복잡한 객체의 대부분을 만들고 조합하는 건 유연하지 않다. 복잡한 객체의 특정 표현을 생성하도록 클래스를 커밋하고 나중에 클래스와 독립적으로(변경할 필요 없이) 표현을 변경할 수 없도록 한다. 클래스는 복잡한 객체의 다른 표현을 만들기 위해 다른 Builder 객체에 위임할 수 있다

장점

1. 제품의 내부 표현을 변경할 수 있다
2. 구성 및 표현을 위한 코드를 캡슐화한다
3. construction process의 단계에 대한 제어를 제공한다

단점

1. 각 제품 유형에 대해 고유한 ConcreteBuilder를 만들어야 한다
2. Builder 클래스는 변경 가능해야 한다
3. 종속성 주입을 방해하거나 복잡하게 만들 수 있다

 

GoF의 디자인 패턴에서는 빌더 패턴의 활용성을 아래와 같이 서술한다.

 

빌더 패턴은 다음의 경우에 사용한다
1. 복합 객체의 생성 알고리즘이 이를 합성하는 요소 객체들이 무엇인지 이들의 조립 방법에 독립적일 때
2. 합성할 객체들의 표현이 서로 다르더라도 생성 절차에서 이를 지원해야 할 때

 

이제 실제로 빌더 패턴을 적용한 예제를 확인해보자.

 

public class NutritionFacts {
    private final int servingSize;
    private final int servings;
    private final int calories;
    private final int fat;
    private final int sodium;
    private final int carbohydrate;

    public static class Builder {
        // 필수 매개변수
        private final int servingSize;
        private final int servings;

        // 선택 매개변수 - 기본값으로 초기화
        private int calories = 0;
        private int fat = 0;
        private int sodium = 0;
        private int carbohydrate = 0;

        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings = servings;
        }

        public Builder setCalories(int val) {
            calories = val;
            return this;
        }

        public Builder setFat(int val) {
            fat = val;
            return this;
        }

        public Builder setSodium(int val) {
            sodium = val;
            return this;
        }

        public Builder setCarbohydrate(int val) {
            carbohydrate = val;
            return this;
        }

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

    private NutritionFacts(Builder builder) {
        servingSize = builder.servingSize;
        servings = builder.servings;
        calories = builder.calories;
        fat = builder.fat;
        sodium = builder.sodium;
        carbohydrate = builder.carbohydrate;
    }
}

 

NutritionFacts 클래스를 사용하는 개발자는 필수 매개변수로 설정한 servingSize, servings의 값만 사용해서 생성자를 호출할 수 있게 된다. 그 외 선택적 매개변수들에 값을 넣는 건 개발자 마음이다. 값을 초기화하지 않으면 기본값으로 설정해둔 0이 입력될 것이다.

실제 사용은 아래와 같이 할 수 있다. 사용해 보면 하나의 객체를 만들기 위해 재료들을 차곡차곡 쌓아서 만들어가는 느낌이라, 어째서 패턴에 Builder라는 이름이 붙었는지 알 것 같기도 하다.

 

public class Main {
    public static void main(String[] args) {
        NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8)
                .setCalories(100)
                .setSodium(35)
                .setCarbohydrate(27)
                .build();
    }
}

 

선택적 매개변수들의 setter들을 없애도 잘 작동한다.

 

public class Main {
    public static void main(String[] args) {
        NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8)
                .build();
    }
}

 

이 빌더 패턴은 생성자나 정적 팩토리가 처리해야 할 매개변수가 많을 경우 사용을 고려해보는 게 좋다. 매개변수 중 여러 개가 필수가 아니거나 같은 타입이라면 더욱 그렇다. 클래스로 만들어 게터세터를 사용하는 자바빈즈 패턴과 여러 생성자를 만들고 각 생성자들이 요구하는 매개변수의 양을 점진적으로 늘려나가는 점층적 생성자 패턴보다는 확실히 빌더 패턴이 좀 더 코드가 눈에 잘 들어온다.

반응형
Comments