본문 바로가기

JAVA/디자인 패턴

[Design Pattern] Builder(빌더) 패턴이란?

반응형
생성 패턴(Creational Pattern)


Builder 패턴은 객체 생성 과정을 캡슐화하여 객체 생성을 단순화하고, 유연성을 높여주는 디자인 패턴입니다.

일반적으로 객체를 생성하는 방법에는 생성자를 이용하는 방법이 있습니다. 그러나 생성자를 이용하면 객체를 생성할 때 모든 매개변수를 전달해야 하기 때문에, 많은 매개변수를 갖는 경우 가독성이 떨어지고 실수하기 쉬워집니다. 또한, 객체의 일부 정보만 알고 있을 경우에는 생성자로 객체를 생성할 수 없습니다.

이러한 문제점을 해결하기 위해 Builder 패턴은 객체 생성 과정을 캡슐화하여 객체 생성을 단순화하고, 유연성을 높여줍니다. Builder 패턴은 객체를 생성하기 위한 별도의 Builder 클래스를 만들어 필요한 정보를 입력받은 후, 객체를 생성하는 방식으로 작동합니다. 이를 이용하면 객체 생성 시 필요한 매개변수를 체이닝 형태로 입력하거나, 일부 필드만 입력할 수 있어 가독성과 유지보수성이 향상됩니다.

또한, Builder 패턴은 객체 생성 시 매개변수의 개수나 종류가 많아도 코드의 가독성을 높일 수 있고, 불필요한 객체 생성을 방지하여 메모리 사용량을 줄일 수 있습니다.

그러므로, 객체 생성 과정을 단순화하고 유연성을 높이기 위해 Builder 패턴을 사용할 수 있습니다.

 

 

Builder 패턴의 장점과 단점

장점

인자가 많은 생성자의 경우, 빌더 패턴을 사용하면 객체 생성 시 인자의 순서에 대해 고민할 필요가 없습니다. 대신에 각각의 인자에 해당하는 메서드를 호출하기 때문에 가독성이 좋아집니다.
빌더를 통해 객체 생성 시, 객체의 일관성과 불변성을 보장할 수 있습니다. 이는 객체의 유효성 검증과 테스트하기 용이하도록 합니다.
빌더 패턴을 사용하면 객체 생성 시 옵션 선택에 따라 필요한 메서드를 호출하면 됩니다. 이는 객체 생성 시 설정할 수 있는 옵션을 명시적으로 알려줌으로써 객체 생성을 보다 쉽고 간결하게 할 수 있습니다.

단점

Builder 패턴을 사용하면 클래스 코드가 복잡해질 수 있습니다. 특히 빌더 클래스가 여러 개인 경우 더 복잡해질 수 있습니다.
빌더 패턴을 사용하면 객체 생성 시 필수 옵션과 선택적 옵션을 나누어야 하기 때문에, 객체 생성 시에 코드가 복잡해질 수 있습니다. 또한, 여러 개의 빌더를 구현하거나 인터페이스를 정의해야 하는 경우도 있습니다.

 

 

Builder 패턴 예제

1. 필수 필드와 선택적 필드를 가진 객체를 생성하는 Builder 패턴


이 예제에서는 일부 필수 매개 변수와 선택적 매개 변수를 가진 객체를 만듭니다. 선택적 매개 변수는 설정하지 않아도 기본값이 있으며, Builder 클래스의 메서드를 사용하여 설정할 수 있습니다.

 

public class Car {
    private final String brand;
    private final String model;
    private final int year;
    private final int price;
    private final String color;
    private final boolean isAutomatic;

    private Car(Builder builder) {
        this.brand = builder.brand;
        this.model = builder.model;
        this.year = builder.year;
        this.price = builder.price;
        this.color = builder.color;
        this.isAutomatic = builder.isAutomatic;
    }

    public static class Builder {
        private final String brand;
        private final String model;
        private final int year;
        private int price;
        private String color;
        private boolean isAutomatic;

        public Builder(String brand, String model, int year) {
            this.brand = brand;
            this.model = model;
            this.year = year;
        }

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

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

        public Builder setIsAutomatic(boolean isAutomatic) {
            this.isAutomatic = isAutomatic;
            return this;
        }

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

 

이제 Car 객체를 생성하고 필요한 매개 변수를 설정할 수 있습니다.

 

Car car = new Car.Builder("Tesla", "Model S", 2022)
        .setPrice(100000)
        .setColor("Red")
        .setIsAutomatic(true)
        .build();

 

 

 

2. 부모 클래스와 자식 클래스에 대한 Builder 패턴

 

public abstract class Vehicle {
    private final String brand;
    private final String model;
    private final int year;
    private int price;
    private String color;
    private boolean isAutomatic;

    protected Vehicle(Builder<?> builder) {
        this.brand = builder.brand;
        this.model = builder.model;
        this.year = builder.year;
        this.price = builder.price;
        this.color = builder.color;
        this.isAutomatic = builder.isAutomatic;
    }

    public String getBrand() {
        return brand;
    }

    public String getModel() {
        return model;
    }

    public int getYear() {
        return year;
    }

    public int getPrice() {
        return price;
    }

    public String getColor() {
        return color;
    }

    public boolean isAutomatic() {
        return isAutomatic;
    }

    public static abstract class Builder<T extends Builder<T>> {
        private final String brand;
        private final String model;
        private final int year;
        private int price;
        private String color;
        private boolean isAutomatic;

        public Builder(String brand, String model, int year) {
            this.brand = brand;
            this.model = model;
            this.year = year;
        }

        public T setPrice(int price) {
            this.price = price;
            return self();
        }

        public T setColor(String color) {
            this.color = color;
            return self();
        }

        public T setIsAutomatic(boolean isAutomatic) {
            this.isAutomatic = isAutomatic;
            return self();
        }

        protected abstract T self();

        public abstract Vehicle build();
    }
}

public class Car extends Vehicle {
    private final int numOfDoors;

    private Car(Builder builder) {
        super(builder);
        this.numOfDoors = builder.numOfDoors;
    }

    public static class Builder extends Vehicle.Builder<Builder> {
        private int numOfDoors;

        public Builder(String brand, String model, int year) {
            super(brand, model, year);
        }

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

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

        @Override
        protected Builder self() {
            return this;
        }
    }
}

public class Motorcycle extends Vehicle {
    private final String type;

    private Motorcycle(Builder builder) {
        super(builder);
        this.type = builder.type;
    }

    public static class Builder extends Vehicle.Builder<Builder> {
        private String type;

        public Builder(String brand, String model, int year) {
            super(brand, model, year);
        }

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

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

        @Override
        protected Builder self() {
            return this;
        }
    }
}

 

이제 다음과 같이 Car와 Motorcycle 객체를 생성할 수 있습니다.

 

Car car = new Car.Builder("Tesla", "Model S", 2022)
        .setPrice(100000)
        .setColor("Red")
        .setIsAutomatic(true)
        .setNumOfDoors(4)
        .build();

Motorcycle motorcycle = new Motorcycle.Builder("Honda", "CBR600RR", 2022)
        .setPrice(12000)
        .setColor("Blue")
        .setIsAutomatic(false)
        .setType("P")
        .build();

 

 

 

3. 가변 인자를 사용하여 객체 생성

 

가변 인자를 사용하여 객체를 생성할 수도 있습니다. 다음은 Pizza 클래스의 예제입니다.

 

public class Pizza {
    private final String size;
    private final List<String> toppings;

    public Pizza(String size, List<String> toppings) {
        this.size = size;
        this.toppings = toppings;
    }

    public String getSize() {
        return size;
    }

    public List<String> getToppings() {
        return toppings;
    }

    public static class Builder {
        private String size;
        private List<String> toppings = new ArrayList<>();

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

        public Builder addTopping(String topping) {
            toppings.add(topping);
            return this;
        }

        public Builder addToppings(String... toppings) {
            this.toppings.addAll(Arrays.asList(toppings));
            return this;
        }

        public Pizza build() {
            return new Pizza(size, toppings);
        }
    }
}

 

 

이제 다음과 같이 Pizza 객체를 생성할 수 있습니다.

 

Pizza pizza = new Pizza.Builder("large")
        .addTopping("pepperoni")
        .addToppings("mushrooms", "onions", "olives")
        .build();
반응형