Builder 디자인 패턴

Builder 디자인 패턴

DesignPattern
Builder 디자인 패턴
Author

gabriel yang

Published

November 12, 2024


Python에서의 Builder 패턴 설명 및 구현

Builder 패턴은 복잡한 객체 생성 과정을 단계별로 나누어 수행하고, 최종적으로 완성된 객체를 반환하는 디자인 패턴입니다. 일반적으로 생성할 객체가 많은 속성을 가지고 있으며, 생성 과정이 복잡할 때 사용됩니다. Python에서는 이 패턴을 통해 여러 옵션을 가지는 객체를 유연하고 일관되게 구성할 수 있습니다. 이번 글에서는 Builder 패턴을 사용하는 이유와 Python에서 이를 구현하는 방법을 설명하겠습니다.

Builder 패턴을 사용하는 이유

Builder 패턴을 사용하는 주된 이유는 다음과 같습니다:

  1. 복잡한 객체 생성의 단순화: 객체가 여러 속성을 가지고 있고, 각 속성의 값에 따라 객체 생성이 복잡해질 때 Builder 패턴을 사용하여 각 속성을 단계별로 설정할 수 있습니다.

  2. 유연한 객체 구성: 객체 생성 시 선택적인 속성이나 단계가 있을 때, Builder 패턴을 사용하면 특정 속성을 제외하거나, 필요에 따라 추가하는 등 유연하게 객체를 구성할 수 있습니다.

  3. 일관성 유지: 동일한 객체를 여러 곳에서 생성할 때, Builder 패턴을 사용하면 객체 생성의 순서와 구성 방식을 표준화하여 일관성을 유지할 수 있습니다.

  4. 확장성: 새로운 속성을 추가하거나 생성 과정을 변경하는 경우, Builder 클래스의 메서드를 추가하거나 수정하여 손쉽게 확장할 수 있습니다.

Builder 패턴의 구조

Builder 패턴은 다음과 같은 구성 요소를 포함합니다:

  • Product: 생성될 객체입니다.
  • Builder: 객체 생성을 위한 단계별 인터페이스 또는 추상 클래스입니다.
  • ConcreteBuilder: Builder 인터페이스를 구현하여 각 단계별 세부 사항을 설정하는 클래스입니다.
  • Director: Builder를 사용하여 객체를 단계별로 생성하는 역할을 담당합니다.

Python에서의 Builder 패턴 구현 예제

아래 예제에서는 Builder 패턴을 사용하여 자동차(Car) 객체를 생성하는 방법을 보여줍니다. 자동차는 좌석 수, 엔진 유형, GPS 유무 등 여러 옵션을 가지고 있으며, 이를 Builder 패턴으로 쉽게 설정할 수 있습니다.

class Car:
    def __init__(self):
        self.seats = None
        self.engine = None
        self.gps = None

    def __str__(self):
        return f"Car(seats={self.seats}, engine={self.engine}, gps={self.gps})"


class CarBuilder:
    def __init__(self):
        self.car = Car()

    def set_seats(self, number):
        self.car.seats = number
        return self  # 메서드 체이닝을 위해 self 반환

    def set_engine(self, engine_type):
        self.car.engine = engine_type
        return self

    def set_gps(self, gps_enabled):
        self.car.gps = gps_enabled
        return self

    def build(self):
        return self.car


class Director:
    def __init__(self, builder):
        self.builder = builder

    def construct_sports_car(self):
        return (self.builder
                .set_seats(2)
                .set_engine("V8")
                .set_gps(True)
                .build())

    def construct_suv(self):
        return (self.builder
                .set_seats(5)
                .set_engine("V6")
                .set_gps(False)
                .build())

이 코드는 Builder 패턴을 사용하여 Car 객체를 단계적으로 생성하는 방식입니다. Builder 패턴을 사용하면 복잡한 객체를 생성하는 과정을 단순화하고 일관성 있게 관리할 수 있습니다. 각 클래스가 어떤 역할을 수행하는지와 코드의 동작 원리를 단계별로 설명하겠습니다.

1. Car 클래스 (Product)

class Car:
    def __init__(self):
        self.seats = None
        self.engine = None
        self.gps = None

    def __str__(self):
        return f"Car(seats={self.seats}, engine={self.engine}, gps={self.gps})"
  • Car 클래스는 생성될 객체로, 자동차의 속성을 정의합니다.
  • self.seats, self.engine, self.gps 속성은 각각 좌석 수, 엔진 종류, GPS 여부를 나타냅니다.
  • __str__ 메서드는 Car 객체의 정보를 문자열로 반환하여, 객체를 쉽게 확인할 수 있게 해줍니다.

2. CarBuilder 클래스 (Builder)

class CarBuilder:
    def __init__(self):
        self.car = Car()
  • CarBuilder 클래스는 Car 객체를 구성하는 빌더 역할을 합니다.
  • self.car = Car()Car 객체를 초기화하여 빌더가 자동차 객체의 속성을 단계적으로 설정할 수 있게 합니다.
    def set_seats(self, number):
        self.car.seats = number
        return self  # 메서드 체이닝을 위해 self 반환
  • set_seats 메서드는 Car 객체의 seats 속성을 설정합니다.
  • 메서드가 self를 반환함으로써 메서드 체이닝을 지원하여, 여러 설정을 순차적으로 호출할 수 있습니다.
    def set_engine(self, engine_type):
        self.car.engine = engine_type
        return self
  • set_engine 메서드는 Car 객체의 engine 속성을 설정합니다.
    def set_gps(self, gps_enabled):
        self.car.gps = gps_enabled
        return self
  • set_gps 메서드는 Car 객체의 gps 속성을 설정합니다.
    def build(self):
        return self.car
  • build 메서드는 최종적으로 완성된 Car 객체를 반환합니다.
  • CarBuilder를 사용하여 설정한 속성들을 포함한 Car 객체가 반환됩니다.

3. Director 클래스

class Director:
    def __init__(self, builder):
        self.builder = builder
  • Director 클래스는 CarBuilder 인스턴스를 받아 특정 설정에 맞는 Car 객체를 구성하는 역할을 합니다.
    def construct_sports_car(self):
        return (self.builder
                .set_seats(2)
                .set_engine("V8")
                .set_gps(True)
                .build())
  • construct_sports_car 메서드는 스포츠카를 구성합니다.
  • set_seats(2), set_engine("V8"), set_gps(True)를 통해 2인승, V8 엔진, GPS가 있는 스포츠카를 생성합니다.
  • 마지막에 build()를 호출하여 완성된 Car 객체를 반환합니다.
    def construct_suv(self):
        return (self.builder
                .set_seats(5)
                .set_engine("V6")
                .set_gps(False)
                .build())
  • construct_suv 메서드는 SUV를 구성합니다.
  • set_seats(5), set_engine("V6"), set_gps(False)를 통해 5인승, V6 엔진, GPS가 없는 SUV를 생성합니다.
  • 최종적으로 build()를 호출하여 구성된 Car 객체를 반환합니다.

사용 예제

builder = CarBuilder()
director = Director(builder)

sports_car = director.construct_sports_car()
print(sports_car)  # 출력: Car(seats=2, engine=V8, gps=True)

suv = director.construct_suv()
print(suv)  # 출력: Car(seats=5, engine=V6, gps=False)
  • CarBuilder 인스턴스를 생성하여, Director가 빌더를 사용하도록 합니다.
  • construct_sports_carconstruct_suv를 호출하여 각각의 설정에 맞는 Car 객체를 생성하고 출력합니다.

Builder 패턴의 장점

  • 유연성: 각 속성을 메서드 체이닝으로 설정할 수 있어 원하는 속성만 선택적으로 적용 가능
  • 확장성: 추가 속성을 쉽게 추가할 수 있어 유지보수가 용이
  • 재사용성: 동일한 빌더를 여러 객체에 재사용 가능
  • 코드 가독성: 객체 생성 코드가 일관되어 가독성이 높아짐

Builder 패턴 다이어그램

다음은 Builder 패턴을 시각적으로 설명하는 UML 다이어그램입니다.

classDiagram
    class Car {
        -int seats
        -str engine
        -bool gps
        +__str__()
    }

    class CarBuilder {
        -Car car
        +set_seats(int): CarBuilder
        +set_engine(str): CarBuilder
        +set_gps(bool): CarBuilder
        +build(): Car
    }

    class Director {
        -CarBuilder builder
        +construct_sports_car(): Car
        +construct_suv(): Car
    }

    Car <-- CarBuilder
    CarBuilder <-- Director

결론

Builder 패턴은 Python에서 복잡한 객체 생성 과정을 단순화하고 유연하게 만드는 데 유용한 패턴입니다. 특히 선택적이거나 설정 가능한 속성이 많은 객체를 생성할 때, 이 패턴을 통해 생성 과정을 단계별로 나누어 일관된 객체를 얻을 수 있습니다.